Merge inbound to m-c. a=merge

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2015-06-18 16:03:38 -04:00
commit 725ca1c6fb
121 changed files with 2212 additions and 1640 deletions

View File

@ -1207,6 +1207,7 @@ pref("security.sandbox.windows.log", false);
// 3 - the strongest settings we seem to be able to use without breaking
// everything, but will probably cause some functionality restrictions
pref("dom.ipc.plugins.sandbox-level.default", 0);
pref("dom.ipc.plugins.sandbox-level.flash", 0);
#if defined(MOZ_CONTENT_SANDBOX)
// This controls the strength of the Windows content process sandbox for testing

View File

@ -145,9 +145,8 @@ SearchSuggestionUIController.prototype = {
this["_on" + event.type[0].toUpperCase() + event.type.substr(1)](event);
},
_onInput: function () {
_onInput: function (event) {
if (this._ignoreInputEvent) {
this._ignoreInputEvent = false;
return;
}
if (this.input.value) {
@ -157,7 +156,7 @@ SearchSuggestionUIController.prototype = {
this._stickyInputValue = "";
this._hideSuggestions();
}
this.selectAndUpdateInput(-1);
this.selectedIndex = -1;
},
_onKeypress: function (event) {
@ -242,15 +241,12 @@ SearchSuggestionUIController.prototype = {
let suggestion = this.suggestionAtIndex(idx);
this._stickyInputValue = suggestion;
// Commit composition string forcibly, because setting input value does not
// work if input has composition string (see bug 1115616 and bug 632744).
// Ignore input event for composition end to avoid getting suggestion again.
// Setting value commits composition string forcibly. While IME commits
// composition, this needs to ignore input event at committed composition
// string which will be overwritten by the suggestion.
this._ignoreInputEvent = true;
this.input.blur();
this.input.focus();
this._ignoreInputEvent = false;
this.input.value = suggestion;
this._ignoreInputEvent = false;
this.input.setAttribute("selection-index", idx);
this.input.setAttribute("selection-kind", "mouse");
this._hideSuggestions();

View File

@ -22,28 +22,17 @@
GLIBCXX_3.4.18 is from gcc 4.8.0 (190787)
GLIBCXX_3.4.19 is from gcc 4.8.1 (199309)
GLIBCXX_3.4.20 is from gcc 4.9.0 (199307)
GLIBCXX_3.4.21 is from gcc 5.0 (210290) */
GLIBCXX_3.4.21 is from gcc 5.0 (210290)
This file adds the necessary compatibility tricks to avoid symbols with
version GLIBCXX_3.4.11 and bigger, keeping binary compatibility with
libstdc++ 4.3.
*/
#define GLIBCXX_VERSION(a, b, c) (((a) << 16) | ((b) << 8) | (c))
namespace std {
#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 9)
/* Instantiate these templates to avoid GLIBCXX_3.4.9 symbol versions */
template ostream& ostream::_M_insert(double);
template ostream& ostream::_M_insert(long);
template ostream& ostream::_M_insert(unsigned long);
template ostream& ostream::_M_insert(long long);
template ostream& ostream::_M_insert(unsigned long long);
template ostream& ostream::_M_insert(bool);
template ostream& ostream::_M_insert(const void*);
template ostream& __ostream_insert(ostream&, const char*, streamsize);
template istream& istream::_M_extract(double&);
template istream& istream::_M_extract(float&);
template istream& istream::_M_extract(unsigned int&);
template istream& istream::_M_extract(unsigned long&);
template istream& istream::_M_extract(unsigned short&);
template istream& istream::_M_extract(unsigned long long&);
#endif
#if MOZ_LIBSTDCXX_VERSION >= GLIBCXX_VERSION(3, 4, 14)
/* Instantiate these templates to avoid GLIBCXX_3.4.14 symbol versions
* depending on optimization level */

View File

@ -631,7 +631,7 @@ EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) $(EXPAND_MKSHLIB_ARGS) -- $(MKSHLIB)
ifneq (,$(MOZ_LIBSTDCXX_TARGET_VERSION)$(MOZ_LIBSTDCXX_HOST_VERSION))
ifneq ($(OS_ARCH),Darwin)
CHECK_STDCXX = @$(TOOLCHAIN_PREFIX)objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo 'TEST-UNEXPECTED-FAIL | check_stdcxx | We do not want these libstdc++ symbols to be used:' && $(TOOLCHAIN_PREFIX)objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && exit 1 || true
CHECK_STDCXX = @$(TOOLCHAIN_PREFIX)objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(1[1-9]\|[2-9][0-9]\)' > /dev/null && echo 'TEST-UNEXPECTED-FAIL | check_stdcxx | We do not want these libstdc++ symbols to be used:' && $(TOOLCHAIN_PREFIX)objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(1[1-9]\|[2-9][0-9]\)' && exit 1 || true
endif
endif

View File

@ -10094,6 +10094,11 @@ nsDocShell::InternalLoad(nsIURI* aURI,
*/
SetHistoryEntry(&mLSHE, aSHEntry);
// Set the doc's URI according to the new history entry's URI.
nsCOMPtr<nsIDocument> doc = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
doc->SetDocumentURI(aURI);
/* This is a anchor traversal with in the same page.
* call OnNewURI() so that, this traversal will be
* recorded in session and global history.
@ -10184,11 +10189,6 @@ nsDocShell::InternalLoad(nsIURI* aURI,
}
}
// Set the doc's URI according to the new history entry's URI.
nsCOMPtr<nsIDocument> doc = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
doc->SetDocumentURI(aURI);
SetDocCurrentStateObj(mOSHE);
// Inform the favicon service that the favicon for oldURI also
@ -11716,8 +11716,8 @@ nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
// document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
// FireOnLocationChange(...) breaks security UI.
if (!equalURIs) {
SetCurrentURI(newURI, nullptr, true, LOCATION_CHANGE_SAME_DOCUMENT);
document->SetDocumentURI(newURI);
SetCurrentURI(newURI, nullptr, true, LOCATION_CHANGE_SAME_DOCUMENT);
AddURIVisit(newURI, oldURI, oldURI, 0);

View File

@ -33,6 +33,7 @@ support-files =
file_bug852909.pdf
file_bug852909.png
file_bug1046022.html
file_multiple_pushState.html
print_postdata.sjs
test-form_sjis.html
timelineMarkers-04.html
@ -98,6 +99,7 @@ skip-if = e10s # Bug ?????? - event handler checks event.target is the content d
skip-if = e10s
[browser_loadURI.js]
skip-if = e10s # Bug ?????? - event handler checks event.target is the content document and test e10s-utils doesn't do that.
[browser_multiple_pushState.js]
[browser_onbeforeunload_navigation.js]
skip-if = e10s
[browser_search_notification.js]

View File

@ -0,0 +1,15 @@
add_task(function* test_multiple_pushState() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "http://example.org/browser/docshell/test/browser/file_multiple_pushState.html",
}, function* (browser) {
const kExpected = "http://example.org/bar/ABC/DEF?key=baz";
let contentLocation = yield ContentTask.spawn(browser, null, function* () {
return content.document.location.href;
});
is(contentLocation, kExpected);
is(browser.documentURI.spec, kExpected);
});
});

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test multiple calls to history.pushState</title>
</head>
<body>
<h1>Ohai</h1>
</body>
<script type="text/javascript">
window.history.pushState({}, "", "/bar/ABC?key=baz");
window.history.pushState({}, "", "/bar/ABC/DEF?key=baz");
</script>
</html>

View File

@ -1785,7 +1785,8 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
}
} else {
// We're going to run these against some non-global scope.
if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script)) {
options.setHasPollutedScope(true);
if (!JS::Compile(cx, options, srcBuf, &script)) {
return;
}
}

View File

@ -805,6 +805,9 @@ UploadLastDir::StoreLastUsedDirectory(nsIDocument* aDoc, nsIFile* aDir)
return NS_ERROR_OUT_OF_MEMORY;
prefValue->SetAsAString(unicodePath);
// Use the document's current load context to ensure that the content pref
// service doesn't persistently store this directory for this domain if the
// user is using private browsing:
nsCOMPtr<nsILoadContext> loadContext = aDoc->GetLoadContext();
return contentPrefService->Set(spec, CPS_PREF_NAME, prefValue, loadContext, nullptr);
}
@ -982,7 +985,7 @@ HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) co
nsAutoString value;
GetValueInternal(value);
// SetValueInternal handles setting the VALUE_CHANGED bit for us
rv = it->SetValueInternal(value, false, true);
rv = it->SetValueInternal(value, nsTextEditorState::eSetValue_Notify);
NS_ENSURE_SUCCESS(rv, rv);
}
break;
@ -1167,7 +1170,8 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
// if @max in the example above were to change from 1 to -1.
nsAutoString value;
GetValue(value);
nsresult rv = SetValueInternal(value, false, false);
nsresult rv =
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
"HTML5 spec does not allow this");
@ -1180,7 +1184,8 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
// See @max comment
nsAutoString value;
GetValue(value);
nsresult rv = SetValueInternal(value, false, false);
nsresult rv =
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
"HTML5 spec does not allow this");
@ -1191,7 +1196,8 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
// See @max comment
nsAutoString value;
GetValue(value);
nsresult rv = SetValueInternal(value, false, false);
nsresult rv =
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
"HTML5 spec does not allow this");
@ -1579,7 +1585,9 @@ HTMLInputElement::SetValue(const nsAString& aValue, ErrorResult& aRv)
nsAutoString currentValue;
GetValue(currentValue);
nsresult rv = SetValueInternal(aValue, false, true);
nsresult rv =
SetValueInternal(aValue, nsTextEditorState::eSetValue_ByContent |
nsTextEditorState::eSetValue_Notify);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;
@ -1589,7 +1597,9 @@ HTMLInputElement::SetValue(const nsAString& aValue, ErrorResult& aRv)
GetValue(mFocusedValue);
}
} else {
nsresult rv = SetValueInternal(aValue, false, true);
nsresult rv =
SetValueInternal(aValue, nsTextEditorState::eSetValue_ByContent |
nsTextEditorState::eSetValue_Notify);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;
@ -2201,7 +2211,9 @@ HTMLInputElement::SetUserInput(const nsAString& aValue)
MozSetFileNameArray(list, rv);
return rv.StealNSResult();
} else {
nsresult rv = SetValueInternal(aValue, true, true);
nsresult rv =
SetValueInternal(aValue, nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -2509,9 +2521,7 @@ HTMLInputElement::UpdateFileList()
}
nsresult
HTMLInputElement::SetValueInternal(const nsAString& aValue,
bool aUserInput,
bool aSetValueChanged)
HTMLInputElement::SetValueInternal(const nsAString& aValue, uint32_t aFlags)
{
NS_PRECONDITION(GetValueMode() != VALUE_MODE_FILENAME,
"Don't call SetValueInternal for file inputs");
@ -2529,12 +2539,13 @@ HTMLInputElement::SetValueInternal(const nsAString& aValue,
}
// else DoneCreatingElement calls us again once mParserCreating is false
if (aSetValueChanged) {
bool setValueChanged = !!(aFlags & nsTextEditorState::eSetValue_Notify);
if (setValueChanged) {
SetValueChanged(true);
}
if (IsSingleLineTextControl(false)) {
if (!mInputData.mState->SetValue(value, aUserInput, aSetValueChanged)) {
if (!mInputData.mState->SetValue(value, aFlags)) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (mType == NS_FORM_INPUT_EMAIL) {
@ -2543,7 +2554,7 @@ HTMLInputElement::SetValueInternal(const nsAString& aValue,
} else {
free(mInputData.mValue);
mInputData.mValue = ToNewUnicode(value);
if (aSetValueChanged) {
if (setValueChanged) {
SetValueChanged(true);
}
if (mType == NS_FORM_INPUT_NUMBER) {
@ -3151,7 +3162,8 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
if (IsExperimentalMobileType(mType)) {
nsAutoString aValue;
GetValueInternal(aValue);
nsresult rv = SetValueInternal(aValue, false, false);
nsresult rv =
SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
NS_ENSURE_SUCCESS(rv, rv);
}
FireChangeEventIfNeeded();
@ -3272,7 +3284,9 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
numberControlFrame->GetValueOfAnonTextControl(value);
numberControlFrame->HandlingInputEvent(true);
nsWeakFrame weakNumberControlFrame(numberControlFrame);
rv = SetValueInternal(value, true, true);
rv = SetValueInternal(value,
nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify);
NS_ENSURE_SUCCESS(rv, rv);
if (weakNumberControlFrame.IsAlive()) {
numberControlFrame->HandlingInputEvent(false);
@ -3349,7 +3363,8 @@ HTMLInputElement::CancelRangeThumbDrag(bool aIsForUserEvent)
ConvertNumberToString(mRangeThumbDragStartValue, val);
// TODO: What should we do if SetValueInternal fails? (The allocation
// is small, so we should be fine here.)
SetValueInternal(val, true, true);
SetValueInternal(val, nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify);
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->UpdateForValueChange();
@ -3369,7 +3384,8 @@ HTMLInputElement::SetValueOfRangeForUserEvent(Decimal aValue)
ConvertNumberToString(aValue, val);
// TODO: What should we do if SetValueInternal fails? (The allocation
// is small, so we should be fine here.)
SetValueInternal(val, true, true);
SetValueInternal(val, nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify);
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->UpdateForValueChange();
@ -3462,7 +3478,8 @@ HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection)
ConvertNumberToString(newValue, newVal);
// TODO: What should we do if SetValueInternal fails? (The allocation
// is small, so we should be fine here.)
SetValueInternal(newVal, true, true);
SetValueInternal(newVal, nsTextEditorState::eSetValue_BySetUserInput |
nsTextEditorState::eSetValue_Notify);
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
static_cast<nsIDOMHTMLInputElement*>(this),
@ -4276,7 +4293,7 @@ HTMLInputElement::HandleTypeChange(uint8_t aNewType)
// TODO: What should we do if SetValueInternal fails? (The allocation
// may potentially be big, but most likely we've failed to allocate
// before the type change.)
SetValueInternal(value, false, false);
SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
}
break;
case VALUE_MODE_FILENAME:
@ -4959,7 +4976,8 @@ HTMLInputElement::SetRangeText(const nsAString& aReplacement, uint32_t aStart,
if (aStart <= aEnd) {
value.Replace(aStart, aEnd - aStart, aReplacement);
nsresult rv = SetValueInternal(value, false, false);
nsresult rv =
SetValueInternal(value, nsTextEditorState::eSetValue_ByContent);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;
@ -5284,7 +5302,7 @@ HTMLInputElement::SetDefaultValueAsValue()
GetDefaultValue(resetVal);
// SetValueInternal is going to sanitize the value.
return SetValueInternal(resetVal, false, false);
return SetValueInternal(resetVal, nsTextEditorState::eSetValue_Internal);
}
void
@ -5525,7 +5543,7 @@ HTMLInputElement::DoneCreatingElement()
// TODO: What should we do if SetValueInternal fails? (The allocation
// may potentially be big, but most likely we've failed to allocate
// before the type change.)
SetValueInternal(aValue, false, false);
SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
}
mShouldInitChecked = false;
@ -5684,7 +5702,8 @@ HTMLInputElement::RestoreState(nsPresState* aState)
// TODO: What should we do if SetValueInternal fails? (The allocation
// may potentially be big, but most likely we've failed to allocate
// before the type change.)
SetValueInternal(inputState->GetValue(), false, true);
SetValueInternal(inputState->GetValue(),
nsTextEditorState::eSetValue_Notify);
break;
}
}

View File

@ -39,8 +39,17 @@ class Date;
class File;
class FileList;
class UploadLastDir final : public nsIObserver, public nsSupportsWeakReference {
/**
* A class we use to create a singleton object that is used to keep track of
* the last directory from which the user has picked files (via
* <input type=file>) on a per-domain basis. The implementation uses
* nsIContentPrefService2/NS_CONTENT_PREF_SERVICE_CONTRACTID to store the last
* directory per-domain, and to ensure that whether the directories are
* persistently saved (saved across sessions) or not honors whether or not the
* page is being viewed in private browsing.
*/
class UploadLastDir final : public nsIObserver, public nsSupportsWeakReference
{
~UploadLastDir() {}
public:
@ -810,9 +819,14 @@ protected:
uint32_t aLen, uint32_t* aResult);
// Helper method
nsresult SetValueInternal(const nsAString& aValue,
bool aUserInput,
bool aSetValueChanged);
/**
* Setting the value.
*
* @param aValue String to set.
* @param aFlags See nsTextEditorState::SetValueFlags.
*/
nsresult SetValueInternal(const nsAString& aValue, uint32_t aFlags);
nsresult GetValueInternal(nsAString& aValue) const;

View File

@ -3110,7 +3110,17 @@ void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
ChangeDelayLoadStatus(false);
GetSrcMediaStream()->AddAudioOutput(this);
SetVolumeInternal();
VideoFrameContainer* container = GetVideoFrameContainer();
bool bUseOverlayImage = mSrcStream->AsDOMHwMediaStream() != nullptr;
VideoFrameContainer* container;
if (bUseOverlayImage) {
container = GetOverlayImageVideoFrameContainer();
}
else {
container = GetVideoFrameContainer();
}
if (container) {
GetSrcMediaStream()->AddVideoOutput(container);
}
@ -3778,7 +3788,23 @@ VideoFrameContainer* HTMLMediaElement::GetVideoFrameContainer()
}
mVideoFrameContainer =
new VideoFrameContainer(this, LayerManager::CreateAsynchronousImageContainer());
new VideoFrameContainer(this, LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS));
return mVideoFrameContainer;
}
VideoFrameContainer* HTMLMediaElement::GetOverlayImageVideoFrameContainer()
{
if (mVideoFrameContainer)
return mVideoFrameContainer;
// Only video frames need an image container.
if (!IsVideo()) {
return nullptr;
}
mVideoFrameContainer =
new VideoFrameContainer(this, LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS_OVERLAY));
return mVideoFrameContainer;
}

View File

@ -212,6 +212,9 @@ public:
virtual bool IsHidden() final override;
// In order to create overlayImageContainer to support DOMHwMediaStream.
VideoFrameContainer* GetOverlayImageVideoFrameContainer();
// Called by the media decoder and the video frame to get the
// ImageContainer containing the video data.
virtual VideoFrameContainer* GetVideoFrameContainer() final override;

View File

@ -297,13 +297,14 @@ HTMLTextAreaElement::GetPlaceholderVisibility()
nsresult
HTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
bool aUserInput)
uint32_t aFlags)
{
// Need to set the value changed flag here, so that
// nsTextControlFrame::UpdateValueDisplay retrieves the correct value
// if needed.
SetValueChanged(true);
if (!mState.SetValue(aValue, aUserInput, true)) {
aFlags |= nsTextEditorState::eSetValue_Notify;
if (!mState.SetValue(aValue, aFlags)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -323,7 +324,8 @@ HTMLTextAreaElement::SetValue(const nsAString& aValue)
nsAutoString currentValue;
GetValueInternal(currentValue, true);
nsresult rv = SetValueInternal(aValue, false);
nsresult rv =
SetValueInternal(aValue, nsTextEditorState::eSetValue_ByContent);
NS_ENSURE_SUCCESS(rv, rv);
if (mFocusedValue.Equals(currentValue)) {
@ -339,7 +341,7 @@ HTMLTextAreaElement::SetUserInput(const nsAString& aValue)
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
return SetValueInternal(aValue, true);
return SetValueInternal(aValue, nsTextEditorState::eSetValue_BySetUserInput);
}
NS_IMETHODIMP
@ -968,7 +970,8 @@ HTMLTextAreaElement::SetRangeText(const nsAString& aReplacement,
if (aStart <= aEnd) {
value.Replace(aStart, aEnd - aStart, aReplacement);
nsresult rv = SetValueInternal(value, false);
nsresult rv =
SetValueInternal(value, nsTextEditorState::eSetValue_ByContent);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;

View File

@ -322,8 +322,14 @@ protected:
*/
void GetValueInternal(nsAString& aValue, bool aIgnoreWrap) const;
nsresult SetValueInternal(const nsAString& aValue,
bool aUserInput);
/**
* Setting the value.
*
* @param aValue String to set.
* @param aFlags See nsTextEditorState::SetValueFlags.
*/
nsresult SetValueInternal(const nsAString& aValue, uint32_t aFlags);
nsresult GetSelectionRange(int32_t* aSelectionStart, int32_t* aSelectionEnd);
/**

View File

@ -27,6 +27,7 @@
#include "nsAttrValueInlines.h"
#include "nsGenericHTMLElement.h"
#include "nsIDOMEventListener.h"
#include "nsIEditorIMESupport.h"
#include "nsIEditorObserver.h"
#include "nsIWidget.h"
#include "nsIDocumentEncoder.h"
@ -1015,15 +1016,16 @@ nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate,
// nsTextEditorState
nsTextEditorState::nsTextEditorState(nsITextControlElement* aOwningElement)
: mTextCtrlElement(aOwningElement),
mBoundFrame(nullptr),
mEverInited(false),
mEditorInitialized(false),
mInitializing(false),
mValueTransferInProgress(false),
mSelectionCached(true),
mSelectionRestoreEagerInit(false),
mPlaceholderVisibility(false)
: mTextCtrlElement(aOwningElement)
, mBoundFrame(nullptr)
, mEverInited(false)
, mEditorInitialized(false)
, mInitializing(false)
, mValueTransferInProgress(false)
, mSelectionCached(true)
, mSelectionRestoreEagerInit(false)
, mPlaceholderVisibility(false)
, mIsCommittingComposition(false)
{
MOZ_COUNT_CTOR(nsTextEditorState);
}
@ -1441,7 +1443,7 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
rv = newEditor->EnableUndo(false);
NS_ENSURE_SUCCESS(rv, rv);
bool success = SetValue(defaultValue, false, false);
bool success = SetValue(defaultValue, eSetValue_Internal);
NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
rv = newEditor->EnableUndo(true);
@ -1705,7 +1707,7 @@ nsTextEditorState::UnbindFromFrame(nsTextControlFrame* aFrame)
// Now that we don't have a frame any more, store the value in the text buffer.
// The only case where we don't do this is if a value transfer is in progress.
if (!mValueTransferInProgress) {
bool success = SetValue(value, false, false);
bool success = SetValue(value, eSetValue_Internal);
// TODO Find something better to do if this fails...
NS_ENSURE_TRUE_VOID(success);
}
@ -1860,6 +1862,15 @@ nsTextEditorState::GetMaxLength(int32_t* aMaxLength)
void
nsTextEditorState::GetValue(nsAString& aValue, bool aIgnoreWrap) const
{
// While SetValue() is being called and requesting to commit composition to
// IME, GetValue() may be called for appending text or something. Then, we
// need to return the latest aValue of SetValue() since the value hasn't
// been set to the editor yet.
if (mIsCommittingComposition) {
aValue = mValueBeingSet;
return;
}
if (mEditor && mBoundFrame && (mEditorInitialized || !IsSingleLineTextControl())) {
bool canCache = aIgnoreWrap && !IsSingleLineTextControl();
if (canCache && !mCachedValue.IsEmpty()) {
@ -1921,9 +1932,73 @@ nsTextEditorState::GetValue(nsAString& aValue, bool aIgnoreWrap) const
}
bool
nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput,
bool aSetValueChanged)
nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
{
nsAutoString newValue(aValue);
// While mIsCommittingComposition is true (that means that some event
// handlers which are fired during committing composition are the caller of
// this method), GetValue() uses mValueBeingSet for its result because the
// first calls of this methods hasn't set the value yet. So, when it's true,
// we need to modify mValueBeingSet. In this case, we will back to the first
// call of this method, then, mValueBeingSet will be truncated when
// mIsCommittingComposition is set false. See below.
if (mIsCommittingComposition) {
mValueBeingSet = aValue;
}
// Note that if this may be called during reframe of the editor. In such
// case, we shouldn't commit composition. Therefore, when this is called
// for internal processing, we shouldn't commit the composition.
if (aFlags & (eSetValue_BySetUserInput | eSetValue_ByContent)) {
if (EditorHasComposition()) {
// When this is called recursively, there shouldn't be composition.
if (NS_WARN_IF(mIsCommittingComposition)) {
// Don't request to commit composition again. But if it occurs,
// we should skip to set the new value to the editor here. It should
// be set later with the updated mValueBeingSet.
return true;
}
// If there is composition, need to commit composition first because
// other browsers do that.
// NOTE: We don't need to block nested calls of this because input nor
// other events won't be fired by setting values and script blocker
// is used during setting the value to the editor. IE also allows
// to set the editor value on the input event which is caused by
// forcibly committing composition.
if (nsContentUtils::IsSafeToRunScript()) {
WeakPtr<nsTextEditorState> self(this);
// WARNING: During this call, compositionupdate, compositionend, input
// events will be fired. Therefore, everything can occur. E.g., the
// document may be unloaded.
mValueBeingSet = aValue;
mIsCommittingComposition = true;
nsCOMPtr<nsIEditorIMESupport> editorIMESupport =
do_QueryInterface(mEditor);
MOZ_RELEASE_ASSERT(editorIMESupport);
nsresult rv = editorIMESupport->ForceCompositionEnd();
if (!self.get()) {
return true;
}
mIsCommittingComposition = false;
// If this is called recursively during committing composition and
// some of them may be skipped above. Therefore, we need to set
// value to the editor with the aValue of the latest call.
newValue = mValueBeingSet;
// When mIsCommittingComposition is false, mValueBeingSet won't be
// used. Therefore, let's clear it.
mValueBeingSet.Truncate();
if (NS_FAILED(rv)) {
NS_WARNING("nsTextEditorState failed to commit composition");
return true;
}
} else {
NS_WARNING("SetValue() is called when there is composition but "
"it's not safe to request to commit the composition");
}
}
}
if (mEditor && mBoundFrame) {
// The InsertText call below might flush pending notifications, which
// could lead into a scheduled PrepareEditor to be called. That will
@ -1945,19 +2020,13 @@ nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput,
nsWeakFrame weakFrame(mBoundFrame);
// this is necessary to avoid infinite recursion
if (!currentValue.Equals(aValue))
if (!currentValue.Equals(newValue))
{
ValueSetter valueSetter(mEditor);
// \r is an illegal character in the dom, but people use them,
// so convert windows and mac platform linebreaks to \n:
// Unfortunately aValue is declared const, so we have to copy
// in order to do this substitution.
nsString newValue;
if (!newValue.Assign(aValue, fallible)) {
return false;
}
if (aValue.FindChar(char16_t('\r')) != -1) {
if (newValue.FindChar(char16_t('\r')) != -1) {
if (!nsContentUtils::PlatformToDOMLineBreaks(newValue, fallible)) {
return false;
}
@ -2020,7 +2089,8 @@ nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput,
mEditor->SetFlags(flags);
mTextListener->SettingValue(true);
mTextListener->SetValueChanged(aSetValueChanged);
bool notifyValueChanged = !!(aFlags & eSetValue_Notify);
mTextListener->SetValueChanged(notifyValueChanged);
// Also don't enforce max-length here
int32_t savedMaxLength;
@ -2043,7 +2113,7 @@ nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput,
// the existing selection -- see bug 574558), in which case we don't
// need to reset the value here.
if (!mBoundFrame) {
return SetValue(newValue, false, aSetValueChanged);
return SetValue(newValue, aFlags & eSetValue_Notify);
}
return true;
}
@ -2065,7 +2135,7 @@ nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput,
mValue = new nsCString;
}
nsString value;
if (!value.Assign(aValue, fallible)) {
if (!value.Assign(newValue, fallible)) {
return false;
}
if (!nsContentUtils::PlatformToDOMLineBreaks(value, fallible)) {
@ -2165,6 +2235,16 @@ nsTextEditorState::HideSelectionIfBlurred()
}
}
bool
nsTextEditorState::EditorHasComposition()
{
bool isComposing = false;
nsCOMPtr<nsIEditorIMESupport> editorIMESupport = do_QueryInterface(mEditor);
return editorIMESupport &&
NS_SUCCEEDED(editorIMESupport->GetComposing(&isComposing)) &&
isComposing;
}
NS_IMPL_ISUPPORTS(nsAnonDivObserver, nsIMutationObserver)
void

View File

@ -143,9 +143,20 @@ public:
nsresult PrepareEditor(const nsAString *aValue = nullptr);
void InitializeKeyboardEventListeners();
enum SetValueFlags
{
// The call is for internal processing.
eSetValue_Internal = 0,
// The value is changed by a call of setUserInput() from chrome.
eSetValue_BySetUserInput = 1 << 0,
// The value is changed by changing value attribute of the element or
// something like setRangeText().
eSetValue_ByContent = 1 << 1,
// Whether the value change should be notified to the frame/contet nor not.
eSetValue_Notify = 1 << 2
};
MOZ_WARN_UNUSED_RESULT bool SetValue(const nsAString& aValue,
bool aUserInput,
bool aSetValueAsChanged);
uint32_t aFlags);
void GetValue(nsAString& aValue, bool aIgnoreWrap) const;
void EmptyValue() { if (mValue) mValue->Truncate(); }
bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; }
@ -244,6 +255,8 @@ private:
mozilla::dom::HTMLInputElement* GetParentNumberControl(nsFrame* aFrame) const;
bool EditorHasComposition();
class InitializationGuard {
public:
explicit InitializationGuard(nsTextEditorState& aState) :
@ -283,14 +296,20 @@ private:
nsAutoPtr<nsCString> mValue;
nsRefPtr<nsAnonDivObserver> mMutationObserver;
mutable nsString mCachedValue; // Caches non-hard-wrapped value on a multiline control.
// mValueBeingSet is available only while SetValue() is requesting to commit
// composition. I.e., this is valid only while mIsCommittingComposition is
// true. While active composition is being committed, GetValue() needs
// the latest value which is set by SetValue(). So, this is cache for that.
nsString mValueBeingSet;
SelectionProperties mSelectionProperties;
bool mEverInited; // Have we ever been initialized?
bool mEditorInitialized;
bool mInitializing; // Whether we're in the process of initialization
bool mValueTransferInProgress; // Whether a value is being transferred to the frame
bool mSelectionCached; // Whether mSelectionProperties is valid
mutable bool mSelectionRestoreEagerInit; // Whether we're eager initing because of selection restore
SelectionProperties mSelectionProperties;
bool mPlaceholderVisibility;
bool mIsCommittingComposition;
};
inline void

View File

@ -41,6 +41,12 @@ parent:
* native HWND of the plugin widget.
*/
sync GetNativePluginPort() returns (uintptr_t value);
/**
* Sends an NS_NATIVE_CHILD_WINDOW to be adopted by the widget's native window
* on the chrome side. This is only currently used on Windows.
*/
sync SetNativeChildWindow(uintptr_t childWindow);
};
}

View File

@ -2645,12 +2645,6 @@ TabParent::TryCacheDPIAndScale()
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget && mFrameElement) {
// Even if we don't have a widget (e.g. because we're display:none), there's
// probably a widget somewhere in the hierarchy our frame element lives in.
widget = nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc());
}
if (widget) {
mDPI = widget->GetDPI();
mDefaultScale = widget->GetDefaultScale();
@ -2660,15 +2654,10 @@ TabParent::TryCacheDPIAndScale()
already_AddRefed<nsIWidget>
TabParent::GetWidget() const
{
nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
if (!content)
if (!mFrameElement) {
return nullptr;
nsIFrame *frame = content->GetPrimaryFrame();
if (!frame)
return nullptr;
nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget();
}
nsCOMPtr<nsIWidget> widget = nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc());
return widget.forget();
}

View File

@ -18,9 +18,13 @@
#include "MediaStreamGraph.h"
#include "AudioStreamTrack.h"
#include "VideoStreamTrack.h"
#include "Layers.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
const TrackID TRACK_VIDEO_PRIMARY = 1;
class DOMMediaStream::StreamListener : public MediaStreamListener {
public:
@ -668,3 +672,112 @@ DOMAudioNodeMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow,
return stream.forget();
}
DOMHwMediaStream::DOMHwMediaStream()
{
#ifdef MOZ_WIDGET_GONK
mImageContainer = LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS_OVERLAY);
nsRefPtr<Image> img = mImageContainer->CreateImage(ImageFormat::OVERLAY_IMAGE);
mOverlayImage = static_cast<layers::OverlayImage*>(img.get());
mImageContainer->SetCurrentImage(mOverlayImage);
#endif
}
DOMHwMediaStream::~DOMHwMediaStream()
{
}
already_AddRefed<DOMHwMediaStream>
DOMHwMediaStream::CreateHwStream(nsIDOMWindow* aWindow)
{
nsRefPtr<DOMHwMediaStream> stream = new DOMHwMediaStream();
stream->InitSourceStream(aWindow);
stream->Init(stream->GetStream());
return stream.forget();
}
void
DOMHwMediaStream::Init(MediaStream* stream)
{
SourceMediaStream* srcStream = stream->AsSourceStream();
if (srcStream) {
VideoSegment segment;
#ifdef MOZ_WIDGET_GONK
const StreamTime delta = STREAM_TIME_MAX; // Because MediaStreamGraph will run out frames in non-autoplay mode,
// we must give it bigger frame length to cover this situation.
mImageData.mOverlayId = DEFAULT_IMAGE_ID;
mImageData.mSize.width = DEFAULT_IMAGE_WIDTH;
mImageData.mSize.height = DEFAULT_IMAGE_HEIGHT;
mOverlayImage->SetData(mImageData);
nsRefPtr<Image> image = static_cast<Image*>(mOverlayImage.get());
mozilla::gfx::IntSize size = image->GetSize();
segment.AppendFrame(image.forget(), delta, size);
#endif
srcStream->AddTrack(TRACK_VIDEO_PRIMARY, 0, new VideoSegment());
srcStream->AppendToTrack(TRACK_VIDEO_PRIMARY, &segment);
srcStream->FinishAddTracks();
srcStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
}
}
int32_t
DOMHwMediaStream::RequestOverlayId()
{
#ifdef MOZ_WIDGET_GONK
return mOverlayImage->GetOverlayId();
#else
return -1;
#endif
}
void
DOMHwMediaStream::SetImageSize(uint32_t width, uint32_t height)
{
#ifdef MOZ_WIDGET_GONK
OverlayImage::Data imgData;
imgData.mOverlayId = mOverlayImage->GetOverlayId();
imgData.mSize = IntSize(width, height);
mOverlayImage->SetData(imgData);
#endif
SourceMediaStream* srcStream = GetStream()->AsSourceStream();
StreamBuffer::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY);
if (!track || !track->GetSegment()) {
return;
}
#ifdef MOZ_WIDGET_GONK
// Clear the old segment.
// Changing the existing content of segment is a Very BAD thing, and this way will
// confuse consumers of MediaStreams.
// It is only acceptable for DOMHwMediaStream
// because DOMHwMediaStream doesn't have consumers of TV streams currently.
track->GetSegment()->Clear();
// Change the image size.
const StreamTime delta = STREAM_TIME_MAX;
nsRefPtr<Image> image = static_cast<Image*>(mOverlayImage.get());
mozilla::gfx::IntSize size = image->GetSize();
VideoSegment segment;
segment.AppendFrame(image.forget(), delta, size);
srcStream->AppendToTrack(TRACK_VIDEO_PRIMARY, &segment);
#endif
}
void
DOMHwMediaStream::SetOverlayId(int32_t aOverlayId)
{
#ifdef MOZ_WIDGET_GONK
OverlayImage::Data imgData;
imgData.mOverlayId = aOverlayId;
imgData.mSize = mOverlayImage->GetSize();
mOverlayImage->SetData(imgData);
#endif
}

View File

@ -6,6 +6,8 @@
#ifndef NSDOMMEDIASTREAM_H_
#define NSDOMMEDIASTREAM_H_
#include "ImageContainer.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "StreamBuffer.h"
@ -29,6 +31,7 @@
namespace mozilla {
class DOMHwMediaStream;
class DOMLocalMediaStream;
class MediaStream;
class MediaEngineSource;
@ -47,6 +50,11 @@ class VideoTrackList;
class MediaTrackListListener;
}
namespace layers {
class ImageContainer;
class OverlayImage;
}
class MediaStreamDirectListener;
#define NS_DOMMEDIASTREAM_IID \
@ -114,6 +122,7 @@ public:
virtual void StopTrack(TrackID aTrackID);
virtual DOMLocalMediaStream* AsDOMLocalMediaStream() { return nullptr; }
virtual DOMHwMediaStream* AsDOMHwMediaStream() { return nullptr; }
bool IsFinished();
/**
@ -375,6 +384,40 @@ private:
nsRefPtr<AudioNode> mStreamNode;
};
class DOMHwMediaStream : public DOMLocalMediaStream
{
typedef mozilla::gfx::IntSize IntSize;
typedef layers::ImageContainer ImageContainer;
#ifdef MOZ_WIDGET_GONK
typedef layers::OverlayImage OverlayImage;
typedef layers::OverlayImage::Data Data;
#endif
public:
DOMHwMediaStream();
static already_AddRefed<DOMHwMediaStream> CreateHwStream(nsIDOMWindow* aWindow);
virtual DOMHwMediaStream* AsDOMHwMediaStream() override { return this; }
int32_t RequestOverlayId();
void SetOverlayId(int32_t aOverlayId);
void SetImageSize(uint32_t width, uint32_t height);
protected:
~DOMHwMediaStream();
private:
void Init(MediaStream* aStream);
#ifdef MOZ_WIDGET_GONK
nsRefPtr<ImageContainer> mImageContainer;
const int DEFAULT_IMAGE_ID = 0x01;
const int DEFAULT_IMAGE_WIDTH = 400;
const int DEFAULT_IMAGE_HEIGHT = 300;
nsRefPtr<OverlayImage> mOverlayImage;
Data mImageData;
#endif
};
}
#endif /* NSDOMMEDIASTREAM_H_ */

View File

@ -2496,6 +2496,12 @@ SourceMediaStream::FinishAddTracks()
}
}
StreamBuffer::Track*
SourceMediaStream::FindTrack(TrackID aID)
{
return mBuffer.FindTrack(aID);
}
void
SourceMediaStream::ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment)
{

View File

@ -801,6 +801,11 @@ public:
*/
void FinishAddTracks();
/**
* Find track by track id.
*/
StreamBuffer::Track* FindTrack(TrackID aID);
/**
* Append media data to a track. Ownership of aSegment remains with the caller,
* but aSegment is emptied.

View File

@ -55,7 +55,7 @@ already_AddRefed<SpeechSynthesisUtterance>
SpeechSynthesisUtterance::Constructor(GlobalObject& aGlobal,
ErrorResult& aRv)
{
return Constructor(aGlobal, NS_LITERAL_STRING(""), aRv);
return Constructor(aGlobal, EmptyString(), aRv);
}
already_AddRefed<SpeechSynthesisUtterance>

View File

@ -299,7 +299,7 @@ nsSpeechTask::DispatchStartImpl(const nsAString& aUri)
mUtterance->mState = SpeechSynthesisUtterance::STATE_SPEAKING;
mUtterance->mChosenVoiceURI = aUri;
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("start"), 0, 0,
NS_LITERAL_STRING(""));
EmptyString());
return NS_OK;
}
@ -370,7 +370,7 @@ nsSpeechTask::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
mUtterance->mPaused = true;
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("pause"),
aCharIndex, aElapsedTime,
NS_LITERAL_STRING(""));
EmptyString());
return NS_OK;
}
@ -397,7 +397,7 @@ nsSpeechTask::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex)
mUtterance->mPaused = false;
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("resume"),
aCharIndex, aElapsedTime,
NS_LITERAL_STRING(""));
EmptyString());
return NS_OK;
}
@ -422,7 +422,7 @@ nsSpeechTask::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex)
mUtterance->mState = SpeechSynthesisUtterance::STATE_ENDED;
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("error"),
aCharIndex, aElapsedTime,
NS_LITERAL_STRING(""));
EmptyString());
return NS_OK;
}

View File

@ -49,7 +49,7 @@ public:
return NS_OK;
}
nsresult GetPluginWidget(nsIWidget **aWidget) {
nsresult GetPluginWidget(nsIWidget **aWidget) const {
NS_IF_ADDREF(*aWidget = mWidget);
return NS_OK;
}

View File

@ -68,7 +68,10 @@ intr protocol PPluginInstance
child:
intr __delete__();
intr NPP_SetWindow(NPRemoteWindow window);
// Return value is only used on Windows and only when the window needs its
// parent set to the chrome widget native window.
intr NPP_SetWindow(NPRemoteWindow window)
returns (NPRemoteWindow childWindowToBeAdopted);
intr NPP_GetValue_NPPVpluginWantsAllNetworkStreams()
returns (bool value, NPError result);

View File

@ -1124,7 +1124,8 @@ void PluginInstanceChild::DeleteWindow()
#endif
bool
PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow,
NPRemoteWindow* aChildWindowToBeAdopted)
{
PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
FULLFUNCTION,
@ -1215,9 +1216,32 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
if (!CreatePluginWindow())
return false;
ReparentPluginWindow(reinterpret_cast<HWND>(aWindow.window));
SizePluginWindow(aWindow.width, aWindow.height);
// If the window is not our parent set the return child window so that
// it can be re-parented in the chrome process. Re-parenting now
// happens there as we might not have sufficient permission.
// Also, this needs to be after SizePluginWindow because SetWindowPos
// relies on things that it sets.
HWND parentWindow = reinterpret_cast<HWND>(aWindow.window);
if (mPluginParentHWND != parentWindow && IsWindow(parentWindow)) {
mPluginParentHWND = parentWindow;
aChildWindowToBeAdopted->window =
reinterpret_cast<uint64_t>(mPluginWindowHWND);
} else {
// Now we know that the window has the correct parent we can show
// it. The actual visibility is controlled by its parent.
// First time round, these calls are made by our caller after the
// parent is set.
ShowWindow(mPluginWindowHWND, SW_SHOWNA);
// This used to be called in SizePluginWindow, but we need to make
// sure that mPluginWindowHWND has had it's parent set correctly,
// otherwise it can cause a focus issue.
SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, aWindow.width,
aWindow.height, SWP_NOZORDER | SWP_NOREPOSITION);
}
mWindow.window = (void*)mPluginWindowHWND;
mWindow.x = aWindow.x;
mWindow.y = aWindow.y;
@ -1405,25 +1429,6 @@ PluginInstanceChild::DestroyPluginWindow()
}
}
void
PluginInstanceChild::ReparentPluginWindow(HWND hWndParent)
{
if (hWndParent != mPluginParentHWND && IsWindow(hWndParent)) {
// Fix the child window's style to be a child window.
LONG_PTR style = GetWindowLongPtr(mPluginWindowHWND, GWL_STYLE);
style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
style &= ~WS_POPUP;
SetWindowLongPtr(mPluginWindowHWND, GWL_STYLE, style);
// Do the reparenting.
SetParent(mPluginWindowHWND, hWndParent);
// Make sure we're visible.
ShowWindow(mPluginWindowHWND, SW_SHOWNA);
}
mPluginParentHWND = hWndParent;
}
void
PluginInstanceChild::SizePluginWindow(int width,
int height)
@ -1431,8 +1436,6 @@ PluginInstanceChild::SizePluginWindow(int width,
if (mPluginWindowHWND) {
mPluginSize.x = width;
mPluginSize.y = height;
SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, width, height,
SWP_NOZORDER | SWP_NOREPOSITION);
}
}

View File

@ -65,7 +65,8 @@ class PluginInstanceChild : public PPluginInstanceChild
#endif
protected:
virtual bool AnswerNPP_SetWindow(const NPRemoteWindow& window) override;
bool AnswerNPP_SetWindow(const NPRemoteWindow& window,
NPRemoteWindow* aChildWindowToBeAdopted) override;
virtual bool
AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(bool* wantsAllStreams, NPError* rv) override;
@ -278,7 +279,6 @@ private:
static bool RegisterWindowClass();
bool CreatePluginWindow();
void DestroyPluginWindow();
void ReparentPluginWindow(HWND hWndParent);
void SizePluginWindow(int width, int height);
int16_t WinlessHandleEvent(NPEvent& event);
void CreateWinlessPopupSurrogate();

View File

@ -49,6 +49,8 @@
#include "mozilla/plugins/PluginSurfaceParent.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#include "nsIWidget.h"
#include "nsPluginNativeWindow.h"
extern const wchar_t* kFlashFullscreenClass;
#elif defined(MOZ_WIDGET_GTK)
#include <gdk/gdk.h>
@ -1025,8 +1027,30 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
window.colormap = ws_info->colormap;
#endif
if (!CallNPP_SetWindow(window))
NPRemoteWindow childWindow;
if (!CallNPP_SetWindow(window, &childWindow)) {
return NPERR_GENERIC_ERROR;
}
#if defined(XP_WIN)
// If a child window is returned it means that we need to re-parent it.
if (childWindow.window) {
nsCOMPtr<nsIWidget> widget;
static_cast<const nsPluginNativeWindow*>(aWindow)->
GetPluginWidget(getter_AddRefs(widget));
if (widget) {
widget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
static_cast<uintptr_t>(childWindow.window));
}
// Now it has got the correct parent, make sure it is visible.
// In subsequent calls to SetWindow these calls happen in the Child.
HWND childHWND = reinterpret_cast<HWND>(childWindow.window);
ShowWindow(childHWND, SW_SHOWNA);
SetWindowPos(childHWND, nullptr, 0, 0, window.width, window.height,
SWP_NOZORDER | SWP_NOREPOSITION);
}
#endif
return NPERR_NO_ERROR;
}

View File

@ -96,17 +96,17 @@ AddSandboxAllowedFiles(int32_t aSandboxLevel,
// Level 2 and above is now using low integrity, so we need to give write
// access to the Flash directories.
// This should be made Flash specific (Bug 1171396).
AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_WIN_APPDATA_DIR,
NS_LITERAL_STRING("\\Macromedia\\Flash Player\\*"));
AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_WIN_APPDATA_DIR,
NS_LITERAL_STRING("\\Adobe\\Flash Player\\*"));
#if defined(_X86_)
// Write access to the Temp directory should only be needed for 32-bit as
// it is used to turn off protected mode, which only applies to x86.
// Write access to the Temp directory is used to turn off protected mode
// and is needed in some mochitest crash tests.
// Bug 1171393 tracks removing this requirement.
AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_OS_TEMP_DIR,
NS_LITERAL_STRING("\\*"));
#endif
}
#endif

View File

@ -210,5 +210,20 @@ PluginWidgetParent::RecvGetNativePluginPort(uintptr_t* value)
return true;
}
bool
PluginWidgetParent::RecvSetNativeChildWindow(const uintptr_t& aChildWindow)
{
#if defined(XP_WIN)
ENSURE_CHANNEL;
PWLOG("PluginWidgetParent::RecvSetNativeChildWindow(%p)\n",
static_cast<void*>(aChildWindow));
mWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW, aChildWindow);
return true;
#else
NS_NOTREACHED("PluginWidgetParent::RecvSetNativeChildWindow not implemented!");
return false;
#endif
}
} // namespace plugins
} // namespace mozilla

View File

@ -31,6 +31,7 @@ public:
virtual bool RecvCreate(nsresult* aResult) override;
virtual bool RecvSetFocus(const bool& aRaise) override;
virtual bool RecvGetNativePluginPort(uintptr_t* value) override;
bool RecvSetNativeChildWindow(const uintptr_t& aChildWindow) override;
// Helper for compositor checks on the channel
bool ActorDestroyed() { return !mWidget; }

View File

@ -197,8 +197,10 @@ TVTuner::GetStream() const
nsresult
TVTuner::InitMediaStream()
{
// TODO Instantiate |mStream| when bug 987498 is done.
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetOwner());
nsRefPtr<DOMHwMediaStream> stream = DOMHwMediaStream::CreateHwStream(window);
mStream = stream.forget();
return NS_OK;
}
@ -218,5 +220,17 @@ TVTuner::DispatchCurrentSourceChangedEvent(TVSource* aSource)
return NS_DispatchToCurrentThread(runnable);
}
nsresult
TVTuner::NotifyImageSizeChanged(uint32_t aWidth, uint32_t aHeight)
{
DOMHwMediaStream* hwMediaStream = mStream->AsDOMHwMediaStream();
if (hwMediaStream) {
hwMediaStream->SetImageSize(aWidth, aHeight);
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla

View File

@ -31,6 +31,7 @@ public:
static already_AddRefed<TVTuner> Create(nsPIDOMWindow* aWindow,
nsITVTunerData* aData);
nsresult NotifyImageSizeChanged(uint32_t aWidth, uint32_t aHeight);
// WebIDL (internal functions)

View File

@ -138,7 +138,7 @@ BufferRecycleBin::GetBuffer(uint32_t aSize)
return result;
}
ImageContainer::ImageContainer(int flag)
ImageContainer::ImageContainer(ImageContainer::Mode flag)
: mReentrantMonitor("ImageContainer.mReentrantMonitor"),
mPaintCount(0),
mPreviousImagePainted(false),
@ -147,11 +147,24 @@ ImageContainer::ImageContainer(int flag)
mCompositionNotifySink(nullptr),
mImageClient(nullptr)
{
if (flag == ENABLE_ASYNC && ImageBridgeChild::IsCreated()) {
if (ImageBridgeChild::IsCreated()) {
// the refcount of this ImageClient is 1. we don't use a RefPtr here because the refcount
// of this class must be done on the ImageBridge thread.
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE).take();
MOZ_ASSERT(mImageClient);
switch(flag) {
case SYNCHRONOUS:
break;
case ASYNCHRONOUS:
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE).take();
MOZ_ASSERT(mImageClient);
break;
case ASYNCHRONOUS_OVERLAY:
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE_OVERLAY).take();
MOZ_ASSERT(mImageClient);
break;
default:
MOZ_ASSERT(false, "This flag is invalid.");
break;
}
}
}

View File

@ -291,9 +291,9 @@ class ImageContainer final : public SupportsWeakPtr<ImageContainer> {
public:
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ImageContainer)
enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 };
enum Mode { SYNCHRONOUS = 0x0, ASYNCHRONOUS = 0x01, ASYNCHRONOUS_OVERLAY = 0x02 };
explicit ImageContainer(int flag = 0);
explicit ImageContainer(ImageContainer::Mode flag = SYNCHRONOUS);
/**
* Create an Image in one of the given formats.

View File

@ -167,16 +167,9 @@ LayerManager::Mutated(Layer* aLayer)
#endif // DEBUG
already_AddRefed<ImageContainer>
LayerManager::CreateImageContainer()
LayerManager::CreateImageContainer(ImageContainer::Mode flag)
{
nsRefPtr<ImageContainer> container = new ImageContainer(ImageContainer::DISABLE_ASYNC);
return container.forget();
}
already_AddRefed<ImageContainer>
LayerManager::CreateAsynchronousImageContainer()
{
nsRefPtr<ImageContainer> container = new ImageContainer(ImageContainer::ENABLE_ASYNC);
nsRefPtr<ImageContainer> container = new ImageContainer(flag);
return container.forget();
}

View File

@ -46,6 +46,7 @@
#include "mozilla/Logging.h" // for PRLogModuleInfo
#include "nsIWidget.h" // For plugin window configuration information structs
#include "gfxVR.h"
#include "ImageContainer.h"
class gfxContext;
@ -81,7 +82,6 @@ class PaintedLayer;
class ContainerLayer;
class ImageLayer;
class ColorLayer;
class ImageContainer;
class CanvasLayer;
class ReadbackLayer;
class ReadbackProcessor;
@ -435,19 +435,12 @@ public:
* Can be called anytime, from any thread.
*
* Creates an Image container which forwards its images to the compositor within
* layer transactions on the main thread.
* layer transactions on the main thread or asynchronously using the ImageBridge IPDL protocol.
* In the case of asynchronous, If the protocol is not available, the returned ImageContainer
* will forward images within layer transactions.
*/
static already_AddRefed<ImageContainer> CreateImageContainer();
/**
* Can be called anytime, from any thread.
*
* Tries to create an Image container which forwards its images to the compositor
* asynchronously using the ImageBridge IPDL protocol. If the protocol is not
* available, the returned ImageContainer will forward images within layer
* transactions, just like if it was created with CreateImageContainer().
*/
static already_AddRefed<ImageContainer> CreateAsynchronousImageContainer();
static already_AddRefed<ImageContainer> CreateImageContainer(ImageContainer::Mode flag
= ImageContainer::SYNCHRONOUS);
/**
* Type of layer manager his is. This is to be used sparsely in order to

View File

@ -363,6 +363,16 @@ ImageHostOverlay::UseOverlaySource(OverlaySource aOverlay)
mOverlay = aOverlay;
}
IntSize
ImageHostOverlay::GetImageSize() const
{
if (mHasPictureRect) {
return IntSize(mPictureRect.width, mPictureRect.height);
}
return IntSize();
}
void
ImageHostOverlay::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{

View File

@ -112,7 +112,8 @@ public:
const nsIntRegion* aVisibleRegion = nullptr) override;
virtual LayerRenderState GetRenderState() override;
virtual void UseOverlaySource(OverlaySource aOverlay) override;
virtual void SetPictureRect(const gfx::IntRect& aPictureRect) override
virtual gfx::IntSize GetImageSize() const override;
virtual void SetPictureRect(const nsIntRect& aPictureRect) override
{
mPictureRect = aPictureRect;
mHasPictureRect = true;

View File

@ -262,7 +262,7 @@ CompositorChild::RecvUpdatePluginConfigurations(const nsIntPoint& aContentOffset
// Tracks visible plugins we update, so we can hide any plugins we don't.
nsTArray<uintptr_t> visiblePluginIds;
nsIWidget* parent = nullptr;
for (uint32_t pluginsIdx = 0; pluginsIdx < aPlugins.Length(); pluginsIdx++) {
nsIWidget* widget =
nsIWidget::LookupRegisteredPluginWindow(aPlugins[pluginsIdx].windowId());
@ -270,6 +270,9 @@ CompositorChild::RecvUpdatePluginConfigurations(const nsIntPoint& aContentOffset
NS_WARNING("Unexpected, plugin id not found!");
continue;
}
if (!parent) {
parent = widget->GetParent();
}
bool isVisible = aPlugins[pluginsIdx].visible();
if (widget && !widget->Destroyed()) {
gfx::IntRect bounds;
@ -321,13 +324,14 @@ CompositorChild::RecvUpdatePluginConfigurations(const nsIntPoint& aContentOffset
}
// Any plugins we didn't update need to be hidden, as they are
// not associated with visible content.
nsIWidget::UpdateRegisteredPluginWindowVisibility(visiblePluginIds);
nsIWidget::UpdateRegisteredPluginWindowVisibility((uintptr_t)parent, visiblePluginIds);
return true;
#endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
}
bool
CompositorChild::RecvUpdatePluginVisibility(nsTArray<uintptr_t>&& aVisibleIdList)
CompositorChild::RecvUpdatePluginVisibility(const uintptr_t& aOwnerWidget,
nsTArray<uintptr_t>&& aVisibleIdList)
{
#if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
NS_NOTREACHED("CompositorChild::RecvUpdatePluginVisibility calls "
@ -335,7 +339,7 @@ CompositorChild::RecvUpdatePluginVisibility(nsTArray<uintptr_t>&& aVisibleIdList
return false;
#else
MOZ_ASSERT(NS_IsMainThread());
nsIWidget::UpdateRegisteredPluginWindowVisibility(aVisibleIdList);
nsIWidget::UpdateRegisteredPluginWindowVisibility(aOwnerWidget, aVisibleIdList);
return true;
#endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
}

View File

@ -88,7 +88,8 @@ public:
nsTArray<PluginWindowData>&& aPlugins) override;
virtual bool
RecvUpdatePluginVisibility(nsTArray<uintptr_t>&& aWindowList) override;
RecvUpdatePluginVisibility(const uintptr_t& aOwnerWidget,
nsTArray<uintptr_t>&& aWindowList) override;
/**
* Request that the parent tell us when graphics are ready on GPU.

View File

@ -1440,12 +1440,9 @@ CompositorParent::AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aB
{
MOZ_ASSERT(aId == 0);
// mWidget doesn't belong to the compositor thread, so it should be set to
// nullptr before returning from this method, to avoid accessing it elsewhere.
gfx::IntRect rect;
mWidget->GetClientBounds(rect);
InitializeLayerManager(aBackendHints);
mWidget = nullptr;
if (!mLayerManager) {
NS_WARNING("Failed to initialise Compositor");
@ -2037,7 +2034,9 @@ UpdatePluginWindowState(uint64_t aId)
// to do here is hide the plugins for the old tree, so don't waste time
// calculating clipping.
nsTArray<uintptr_t> aVisibleIdList;
unused << lts.mParent->SendUpdatePluginVisibility(aVisibleIdList);
uintptr_t parentWidget = (uintptr_t)lts.mParent->GetWidget();
unused << lts.mParent->SendUpdatePluginVisibility(parentWidget,
aVisibleIdList);
lts.mUpdatedPluginDataAvailable = false;
return;
}

View File

@ -424,6 +424,8 @@ public:
*/
static bool IsInCompositorThread();
nsIWidget* GetWidget() { return mWidget; }
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~CompositorParent();

View File

@ -69,7 +69,8 @@ child:
* Sets the list of currently visible plugin windows based on a
* list of plugin window ids.
*/
async UpdatePluginVisibility(uintptr_t[] aVisibleIdList);
async UpdatePluginVisibility(uintptr_t aOwnerWidget,
uintptr_t[] aVisibleIdList);
/**
* Drop any buffers that might be retained on the child compositor

View File

@ -670,10 +670,6 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
}
}
// Clear any cached plugin data we might have, now that the
// transaction is complete.
mPluginWindowData.Clear();
*aSent = true;
mIsFirstPaint = false;
MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));

View File

@ -514,7 +514,6 @@ public:
}
mPreviousTimestamp = TimeStamp::Now();
mStartingVsync = true;
if (CVDisplayLinkStart(mDisplayLink) != kCVReturnSuccess) {
NS_WARNING("Could not activate the display link");
CVDisplayLinkRelease(mDisplayLink);
@ -548,7 +547,6 @@ public:
// Normalize the timestamps given to the VsyncDispatchers to the vsync
// that just occured, not the vsync that is upcoming.
TimeStamp mPreviousTimestamp;
bool mStartingVsync;
private:
// Manages the display link render thread
@ -574,30 +572,26 @@ static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink,
// Executed on OS X hardware vsync thread
OSXVsyncSource::OSXDisplay* display = (OSXVsyncSource::OSXDisplay*) aDisplayLinkContext;
int64_t nextVsyncTimestamp = aOutputTime->hostTime;
mozilla::TimeStamp nextVsync = mozilla::TimeStamp::FromSystemTime(nextVsyncTimestamp);
mozilla::TimeStamp previousVsync = display->mPreviousTimestamp;
bool firstVsync = display->mStartingVsync;
display->mStartingVsync = false;
display->mPreviousTimestamp = nextVsync;
mozilla::TimeStamp now = TimeStamp::Now();
if (nextVsync <= previousVsync) {
TimeDuration next = nextVsync - now;
TimeDuration prev = now - previousVsync;
printf_stderr("Next from now: %f, prev from now: %f, first vsync %d\n",
next.ToMilliseconds(), prev.ToMilliseconds(), firstVsync);
MOZ_ASSERT(false, "Next vsync less than previous vsync\n");
}
// Bug 1158321 - The VsyncCallback can sometimes execute before the reported
// vsync time. In those cases, normalize the timestamp to Now() as sending
// timestamps in the future has undefined behavior. See the comment above
// OSXDisplay::mPreviousTimestamp
if (now < previousVsync) {
// Snow leopard sometimes sends vsync timestamps very far in the past.
// Normalize the vsync timestamps to now.
if (nextVsync <= previousVsync) {
nextVsync = now;
previousVsync = now;
} else if (now < previousVsync) {
// Bug 1158321 - The VsyncCallback can sometimes execute before the reported
// vsync time. In those cases, normalize the timestamp to Now() as sending
// timestamps in the future has undefined behavior. See the comment above
// OSXDisplay::mPreviousTimestamp
previousVsync = now;
}
display->mPreviousTimestamp = nextVsync;
display->NotifyVsync(previousVsync);
return kCVReturnSuccess;
}

View File

@ -22,13 +22,13 @@ public:
NS_IMETHOD Convert(const char* aSrc,
int32_t* aSrcLength,
char16_t* aDest,
int32_t* aDestLength);
int32_t* aDestLength) override;
MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char* aSrc,
int32_t aSrcLength,
int32_t* aDestLength) override;
NS_IMETHOD Reset();
NS_IMETHOD Reset() override;
private:
bool mSeenByte;

View File

@ -57,12 +57,12 @@ protected:
// Subclassing of nsBasicDecoderSupport class [declaration]
NS_IMETHOD Convert(const char * aSrc, int32_t * aSrcLength,
char16_t * aDest, int32_t * aDestLength);
char16_t * aDest, int32_t * aDestLength) override;
//--------------------------------------------------------------------
// Subclassing of nsBasicDecoderSupport class [declaration]
NS_IMETHOD Reset();
NS_IMETHOD Reset() override;
};

View File

@ -27,7 +27,7 @@ public:
MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char* aSrc,
int32_t aSrcLength,
int32_t* aDestLength) override;
NS_IMETHOD Reset();
NS_IMETHOD Reset() override;
protected:
uint8_t mState;

View File

@ -212,6 +212,18 @@ TryEvalJSON(JSContext* cx, JSLinearString* str, MutableHandleValue rval)
: ParseEvalStringAsJSON(cx, linearChars.twoByteRange(), rval);
}
static bool
HasPollutedScopeChain(JSObject* scopeChain)
{
while (scopeChain) {
if (scopeChain->is<DynamicWithObject>())
return true;
scopeChain = scopeChain->enclosingScope();
}
return false;
}
// Define subset of ExecuteType so that casting performs the injection.
enum EvalType { DIRECT_EVAL = EXECUTE_DIRECT_EVAL, INDIRECT_EVAL = EXECUTE_INDIRECT_EVAL };
@ -238,6 +250,12 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
return false;
}
if (evalType == DIRECT_EVAL && caller.script()->isDerivedClassConstructor()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DISABLED_DERIVED_CLASS,
"direct eval");
return false;
}
// ES5 15.1.2.1 step 1.
if (args.length() < 1) {
args.rval().setUndefined();
@ -314,8 +332,13 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
if (!staticScope)
return false;
bool hasPollutedGlobalScope =
HasPollutedScopeChain(scopeobj) ||
(evalType == DIRECT_EVAL && callerScript->hasPollutedGlobalScope());
CompileOptions options(cx);
options.setFileAndLine(filename, 1)
.setHasPollutedScope(hasPollutedGlobalScope)
.setIsRunOnce(true)
.setForEval(true)
.setNoScriptRval(false)
@ -333,7 +356,7 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame
: SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
JSScript* compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scopeobj, staticScope, callerScript,
scopeobj, callerScript, staticScope,
options, srcBuf, linearStr, staticLevel);
if (!compiled)
return false;
@ -387,7 +410,7 @@ js::DirectEvalStringFromIon(JSContext* cx,
bool mutedErrors;
uint32_t pcOffset;
DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset,
&mutedErrors, CALLED_FROM_JSOP_EVAL);
&mutedErrors, CALLED_FROM_JSOP_EVAL);
const char* introducerFilename = filename;
if (maybeScript && maybeScript->scriptSource()->introducerFilename())
@ -400,6 +423,8 @@ js::DirectEvalStringFromIon(JSContext* cx,
CompileOptions options(cx);
options.setFileAndLine(filename, 1)
.setHasPollutedScope(HasPollutedScopeChain(scopeobj) ||
callerScript->hasPollutedGlobalScope())
.setIsRunOnce(true)
.setForEval(true)
.setNoScriptRval(false)
@ -417,7 +442,7 @@ js::DirectEvalStringFromIon(JSContext* cx,
: SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
JSScript* compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scopeobj, staticScope, callerScript,
scopeobj, callerScript, staticScope,
options, srcBuf, linearStr, staticLevel);
if (!compiled)
return false;
@ -488,31 +513,35 @@ js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScri
CHECK_REQUEST(cx);
assertSameCompartment(cx, global);
MOZ_ASSERT(global->is<GlobalObject>());
MOZ_RELEASE_ASSERT(scriptArg->hasNonSyntacticScope());
MOZ_RELEASE_ASSERT(scriptArg->hasPollutedGlobalScope());
RootedScript script(cx, scriptArg);
if (script->compartment() != cx->compartment()) {
Rooted<ScopeObject*> staticScope(cx, StaticNonSyntacticScopeObjects::create(cx, nullptr));
if (!staticScope)
return false;
script = CloneGlobalScript(cx, staticScope, script);
script = CloneScript(cx, nullptr, nullptr, script);
if (!script)
return false;
Debugger::onNewScript(cx, script);
}
Rooted<GlobalObject*> globalRoot(cx, &global->as<GlobalObject>());
Rooted<ScopeObject*> scope(cx, NonSyntacticVariablesObject::create(cx, globalRoot));
RootedObject scope(cx, JS_NewPlainObject(cx));
if (!scope)
return false;
if (!scope->setQualifiedVarObj(cx))
return false;
if (!scope->setUnqualifiedVarObj(cx))
return false;
JSObject* thisobj = GetThisObject(cx, global);
if (!thisobj)
return false;
RootedValue thisv(cx, ObjectValue(*thisobj));
RootedValue rval(cx);
// XXXbz when this is fixed to pass in an actual ScopeObject, fix
// up the assert in js::CloneFunctionObject accordingly.
if (!ExecuteKernel(cx, script, *scope, thisv, UndefinedValue(), EXECUTE_GLOBAL,
NullFramePtr() /* evalInFrame */, rval.address()))
{

View File

@ -2272,10 +2272,11 @@ EvalReturningScope(JSContext* cx, unsigned argc, jsval* vp)
JS::CompileOptions options(cx);
options.setFileAndLine(filename.get(), lineno);
options.setNoScriptRval(true);
options.setHasPollutedScope(true);
JS::SourceBufferHolder srcBuf(src, srclen, JS::SourceBufferHolder::NoOwnership);
RootedScript script(cx);
if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script))
if (!JS::Compile(cx, options, srcBuf, &script))
return false;
if (global) {

View File

@ -144,11 +144,10 @@ MaybeCheckEvalFreeVariables(ExclusiveContext* cxArg, HandleScript evalCaller, Ha
}
static inline bool
CanLazilyParse(ExclusiveContext* cx, HandleObject staticScope,
const ReadOnlyCompileOptions& options)
CanLazilyParse(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
{
return options.canLazilyParse &&
!HasNonSyntacticStaticScopeChain(staticScope) &&
!options.hasPollutedGlobalScope &&
!cx->compartment()->options().disableLazyParsing() &&
!cx->compartment()->options().discardSource() &&
!options.sourceIsLazy;
@ -211,8 +210,8 @@ frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOp
JSScript*
frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject scopeChain,
Handle<ScopeObject*> enclosingStaticScope,
HandleScript evalCaller,
Handle<StaticEvalObject*> evalStaticScope,
const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf,
JSString* source_ /* = nullptr */,
@ -261,7 +260,7 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
return nullptr;
}
bool canLazilyParse = CanLazilyParse(cx, enclosingStaticScope, options);
bool canLazilyParse = CanLazilyParse(cx, options);
Maybe<Parser<SyntaxParseHandler> > syntaxParser;
if (canLazilyParse) {
@ -285,22 +284,22 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
bool savedCallerFun = evalCaller && evalCaller->functionOrCallerFunction();
Directives directives(options.strictOption);
GlobalSharedContext globalsc(cx, directives, enclosingStaticScope, options.extraWarningsOption);
GlobalSharedContext globalsc(cx, directives, evalStaticScope, options.extraWarningsOption);
Rooted<JSScript*> script(cx, JSScript::Create(cx, enclosingStaticScope, savedCallerFun,
Rooted<JSScript*> script(cx, JSScript::Create(cx, evalStaticScope, savedCallerFun,
options, staticLevel, sourceObject, 0,
srcBuf.length()));
if (!script)
return nullptr;
bool insideNonGlobalEval =
enclosingStaticScope && enclosingStaticScope->is<StaticEvalObject>() &&
enclosingStaticScope->as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
evalStaticScope && evalStaticScope->enclosingScopeForStaticScopeIter();
BytecodeEmitter::EmitterMode emitterMode =
options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script,
/* lazyScript = */ nullptr, options.forEval,
evalCaller, insideNonGlobalEval, options.lineno, emitterMode);
evalCaller, insideNonGlobalEval,
options.lineno, emitterMode);
if (!bce.init())
return nullptr;
@ -562,7 +561,7 @@ CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyComp
return false;
}
bool canLazilyParse = CanLazilyParse(cx, enclosingStaticScope, options);
bool canLazilyParse = CanLazilyParse(cx, options);
Maybe<Parser<SyntaxParseHandler> > syntaxParser;
if (canLazilyParse) {

View File

@ -17,17 +17,18 @@ class AutoNameVector;
class LazyScript;
class LifoAlloc;
class ScriptSourceObject;
class ScopeObject;
class StaticEvalObject;
struct SourceCompressionTask;
namespace frontend {
JSScript*
CompileScript(ExclusiveContext* cx, LifoAlloc* alloc,
HandleObject scopeChain, Handle<ScopeObject*> enclosingStaticScope,
HandleScript evalCaller, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, JSString* source_ = nullptr,
unsigned staticLevel = 0, SourceCompressionTask* extraSct = nullptr);
HandleObject scopeChain, HandleScript evalCaller,
Handle<StaticEvalObject*> evalStaticScope,
const ReadOnlyCompileOptions& options, SourceBufferHolder& srcBuf,
JSString* source_ = nullptr, unsigned staticLevel = 0,
SourceCompressionTask* extraSct = nullptr);
bool
CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);

View File

@ -769,7 +769,7 @@ BytecodeEmitter::enclosingStaticScope()
// Top-level eval scripts have a placeholder static scope so that
// StaticScopeIter may iterate through evals.
return sc->asGlobalSharedContext()->topStaticScope();
return sc->asGlobalSharedContext()->evalStaticScope();
}
return sc->asFunctionBox()->function();
@ -1548,14 +1548,14 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn)
// Use generic ops if a catch block is encountered.
return false;
}
if (ssi.hasSyntacticDynamicScopeObject())
if (ssi.hasDynamicScopeObject())
hops++;
continue;
}
RootedScript script(cx, ssi.funScript());
if (script->functionNonDelazifying()->atom() == pn->pn_atom)
return false;
if (ssi.hasSyntacticDynamicScopeObject()) {
if (ssi.hasDynamicScopeObject()) {
uint32_t slot;
if (lookupAliasedName(script, pn->pn_atom->asPropertyName(), &slot, pn)) {
JSOp op;
@ -1587,9 +1587,9 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn)
if (insideNonGlobalEval)
return false;
// Skip trying to use GNAME ops if we know our script has a non-syntactic
// scope, since they'll just get treated as NAME ops anyway.
if (script->hasNonSyntacticScope())
// Skip trying to use GNAME ops if we know our script has a polluted
// global scope, since they'll just get treated as NAME ops anyway.
if (script->hasPollutedGlobalScope())
return false;
// Deoptimized names also aren't necessarily globals.
@ -2356,14 +2356,13 @@ BytecodeEmitter::checkRunOnceContext()
bool
BytecodeEmitter::needsImplicitThis()
{
if (sc->inWith())
if (sc->isFunctionBox() && sc->asFunctionBox()->inWith)
return true;
for (StmtInfoBCE* stmt = topStmt; stmt; stmt = stmt->down) {
if (stmt->type == STMT_WITH)
return true;
}
return false;
}
@ -3407,19 +3406,6 @@ BytecodeEmitter::emitFunctionScript(ParseNode* body)
*/
FunctionBox* funbox = sc->asFunctionBox();
// Link the function and the script to each other, so that StaticScopeIter
// may walk the scope chain of currently compiling scripts.
RootedFunction fun(cx, funbox->function());
MOZ_ASSERT(fun->isInterpreted());
script->setFunction(fun);
if (fun->isInterpretedLazy())
fun->setUnlazifiedScript(script);
else
fun->setScript(script);
if (funbox->argumentsHasLocalBinding()) {
MOZ_ASSERT(offset() == 0); /* See JSScript::argumentsBytecode. */
switchToPrologue();
@ -3523,6 +3509,15 @@ BytecodeEmitter::emitFunctionScript(ParseNode* body)
MOZ_ASSERT(!script->hasRunOnce());
}
/* Initialize fun->script() so that the debugger has a valid fun->script(). */
RootedFunction fun(cx, script->functionNonDelazifying());
MOZ_ASSERT(fun->isInterpreted());
if (fun->isInterpretedLazy())
fun->setUnlazifiedScript(script);
else
fun->setScript(script);
tellDebuggerAboutCompiledScript(cx);
return true;
@ -5770,6 +5765,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
Rooted<JSScript*> parent(cx, script);
CompileOptions options(cx, parser->options());
options.setMutedErrors(parent->mutedErrors())
.setHasPollutedScope(parent->hasPollutedGlobalScope())
.setSelfHostingMode(parent->selfHosted())
.setNoScriptRval(false)
.setForEval(false)
.setVersion(parent->getVersion());

View File

@ -22,7 +22,7 @@
namespace js {
class ScopeObject;
class StaticEvalObject;
namespace frontend {

View File

@ -637,6 +637,10 @@ class FullParseHandler
void addFunctionArgument(ParseNode* pn, ParseNode* argpn) {
pn->pn_body->append(argpn);
}
void setDerivedClassConstructor(ParseNode* pn) {
MOZ_ASSERT(pn->isKind(PNK_FUNCTION));
pn->pn_funbox->setDerivedClassConstructor();
}
ParseNode* newLexicalScope(ObjectBox* blockBox) {
return new_<LexicalScopeNode>(blockBox, pos());

View File

@ -1699,6 +1699,7 @@ enum FunctionSyntaxKind
Arrow,
Method,
ClassConstructor,
DerivedClassConstructor,
Getter,
Setter
};

View File

@ -596,7 +596,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct
bufEnd(0),
length(0),
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
inWith_(false), // initialized below
inWith(false), // initialized below
inGenexpLambda(false),
hasDestructuringArgs(false),
useAsm(false),
@ -612,7 +612,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct
MOZ_ASSERT(fun->isTenured());
if (!outerpc) {
inWith_ = false;
inWith = false;
} else if (outerpc->parsingWith) {
// This covers cases that don't involve eval(). For example:
@ -621,7 +621,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct
//
// In this case, |outerpc| corresponds to global code, and
// outerpc->parsingWith is true.
inWith_ = true;
inWith = true;
} else if (outerpc->sc->isFunctionBox()) {
// This is like the above case, but for more deeply nested functions.
@ -632,17 +632,8 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct
// In this case, the inner anonymous function needs to inherit the
// setting of |inWith| from the outer one.
FunctionBox* parent = outerpc->sc->asFunctionBox();
if (parent && parent->inWith())
inWith_ = true;
} else {
// This is like the above case, but when inside eval.
//
// For example:
//
// with(o) { eval("(function() { g(); })();"); }
//
// In this case, the static scope chain tells us the presence of with.
inWith_ = outerpc->sc->inWith();
if (parent && parent->inWith)
inWith = true;
}
}
@ -828,14 +819,30 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoN
if (!FoldConstants(context, &pn, this))
return null();
fn->pn_pos.end = pos().end;
MOZ_ASSERT(fn->pn_body->isKind(PNK_ARGSBODY));
fn->pn_body->append(pn);
/*
* Make sure to deoptimize lexical dependencies that are polluted
* by eval and function statements (which both flag the function as
* having an extensible scope).
*/
if (funbox->hasExtensibleScope() && pc->lexdeps->count()) {
for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) {
Definition* dn = r.front().value().get<FullParseHandler>();
MOZ_ASSERT(dn->isPlaceholder());
handler.deoptimizeUsesWithin(dn, fn->pn_pos);
}
}
InternalHandle<Bindings*> funboxBindings =
InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
if (!funpc.generateFunctionBindings(context, tokenStream, alloc, funboxBindings))
return null();
MOZ_ASSERT(fn->pn_body->isKind(PNK_ARGSBODY));
fn->pn_body->append(pn);
fn->pn_body->pn_pos = pn->pn_pos;
return fn;
}
@ -1219,6 +1226,7 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case ClassConstructor:
case DerivedClassConstructor:
flags = JSFunction::INTERPRETED_CLASS_CONSTRUCTOR;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
@ -2224,7 +2232,7 @@ Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox* funbo
// while its ParseContext and associated lexdeps and inner functions are
// still available.
if (funbox->inWith())
if (funbox->inWith)
return abortIfSyntaxParser();
size_t numFreeVariables = pc->lexdeps->count();
@ -2252,6 +2260,8 @@ Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox* funbo
lazy->setGeneratorKind(funbox->generatorKind());
if (funbox->usesArguments && funbox->usesApply && funbox->usesThis)
lazy->setUsesArgumentsApplyAndThis();
if (funbox->isDerivedClassConstructor())
lazy->setIsDerivedClassConstructor();
PropagateTransitiveParseFlags(funbox, lazy);
fun->initLazyScript(lazy);
@ -2273,6 +2283,9 @@ Parser<FullParseHandler>::functionArgsAndBody(InHandling inHandling, ParseNode*
if (!funbox)
return false;
if (kind == DerivedClassConstructor)
funbox->setDerivedClassConstructor();
YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
// Try a syntax parse for this inner function.
@ -2435,6 +2448,9 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned st
return null();
funbox->length = fun->nargs() - fun->hasRest();
if (fun->lazyScript()->isDerivedClassConstructor())
funbox->setDerivedClassConstructor();
Directives newDirectives = directives;
ParseContext<FullParseHandler> funpc(this, /* parent = */ nullptr, pn, funbox,
&newDirectives, staticLevel, /* bodyid = */ 0,
@ -5969,7 +5985,8 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CLASS);
ParseNode* classMethods = propertyList(yieldHandling, ClassBody);
ParseNode* classMethods = propertyList(yieldHandling,
hasHeritage ? DerivedClassBody : ClassBody);
if (!classMethods)
return null();
@ -6546,6 +6563,11 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (!tokenStream.peekToken(&ignored))
return null();
if (pc->sc->isFunctionBox() && pc->sc->asFunctionBox()->isDerivedClassConstructor()) {
report(ParseError, false, null(), JSMSG_DISABLED_DERIVED_CLASS, "arrow functions");
return null();
}
return functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator);
}
@ -8316,7 +8338,7 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::newPropertyListNode(PropListType type)
{
if (type == ClassBody)
if (IsClassBody(type))
return handler.newClassMethodList(pos().begin);
MOZ_ASSERT(type == ObjectLiteral);
@ -8344,7 +8366,7 @@ Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType typ
break;
bool isStatic = false;
if (type == ClassBody) {
if (IsClassBody(type)) {
if (ltok == TOK_SEMI)
continue;
@ -8484,7 +8506,7 @@ Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType typ
}
}
if (type == ClassBody) {
if (IsClassBody(type)) {
if (!isStatic && atom == context->names().constructor) {
if (isGenerator || op != JSOP_INITPROP) {
report(ParseError, false, propname, JSMSG_BAD_METHOD_DEF);
@ -8508,7 +8530,7 @@ Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType typ
return null();
if (tt == TOK_COLON) {
if (type == ClassBody) {
if (IsClassBody(type)) {
report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF);
return null();
}
@ -8550,7 +8572,7 @@ Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType typ
* Support, e.g., |var {x, y} = o| as destructuring shorthand
* for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
*/
if (type == ClassBody) {
if (IsClassBody(type)) {
report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF);
return null();
}
@ -8572,7 +8594,9 @@ Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType typ
} else if (tt == TOK_LP) {
tokenStream.ungetToken();
if (!methodDefinition(yieldHandling, type, propList, propname,
isConstructor ? ClassConstructor : Method,
isConstructor ? type == DerivedClassBody ? DerivedClassConstructor
: ClassConstructor
: Method,
isGenerator ? StarGenerator : NotGenerator, isStatic, op))
{
return null();
@ -8604,7 +8628,7 @@ Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType typ
}
// Default constructors not yet implemented. See bug 1105463
if (type == ClassBody && !seenConstructor) {
if (IsClassBody(type) && !seenConstructor) {
report(ParseError, false, null(), JSMSG_NO_CLASS_CONSTRUCTOR);
return null();
}
@ -8619,19 +8643,23 @@ Parser<ParseHandler>::methodDefinition(YieldHandling yieldHandling, PropListType
Node propList, Node propname, FunctionSyntaxKind kind,
GeneratorKind generatorKind, bool isStatic, JSOp op)
{
MOZ_ASSERT(kind == Method || kind == ClassConstructor || kind == Getter || kind == Setter);
MOZ_ASSERT(kind == Method || kind == ClassConstructor || kind == DerivedClassConstructor ||
kind == Getter || kind == Setter);
/* NB: Getter function in { get x(){} } is unnamed. */
RootedPropertyName funName(context);
if ((kind == Method || kind == ClassConstructor) && tokenStream.isCurrentTokenType(TOK_NAME))
if ((kind == Method || kind == ClassConstructor || kind == DerivedClassConstructor) &&
tokenStream.isCurrentTokenType(TOK_NAME))
{
funName = tokenStream.currentName();
else
} else {
funName = nullptr;
}
Node fn = functionDef(InAllowed, yieldHandling, funName, kind, generatorKind);
if (!fn)
return false;
if (listType == ClassBody)
if (IsClassBody(listType))
return handler.addClassMethodDefinition(propList, propname, fn, op, isStatic);
MOZ_ASSERT(listType == ObjectLiteral);

View File

@ -323,7 +323,13 @@ struct BindData;
class CompExprTransplanter;
enum VarContext { HoistVars, DontHoistVars };
enum PropListType { ObjectLiteral, ClassBody };
enum PropListType { ObjectLiteral, ClassBody, DerivedClassBody };
inline bool
IsClassBody(PropListType type)
{
return type == ClassBody || type == DerivedClassBody;
}
// Specify a value for an ES6 grammar parametrization. We have no enum for
// [Return] because its behavior is exactly equivalent to checking whether

View File

@ -127,6 +127,7 @@ class FunctionContextFlags
bool definitelyNeedsArgsObj:1;
bool needsHomeObject:1;
bool isDerivedClassConstructor:1;
public:
FunctionContextFlags()
@ -135,7 +136,8 @@ class FunctionContextFlags
needsDeclEnvObject(false),
argumentsHasLocalBinding(false),
definitelyNeedsArgsObj(false),
needsHomeObject(false)
needsHomeObject(false),
isDerivedClassConstructor(false)
{ }
};
@ -235,7 +237,6 @@ class SharedContext
SuperProperty
};
virtual bool allowSyntax(AllowedSyntax allowed) const = 0;
virtual bool inWith() const = 0;
protected:
static bool FunctionAllowsSyntax(JSFunction* func, AllowedSyntax allowed)
@ -257,13 +258,21 @@ class SharedContext
class GlobalSharedContext : public SharedContext
{
private:
Handle<ScopeObject*> topStaticScope_;
bool allowNewTarget_;
bool allowSuperProperty_;
bool inWith_;
Handle<StaticEvalObject*> staticEvalScope_;
bool computeAllowSyntax(AllowedSyntax allowed) const {
StaticScopeIter<CanGC> it(context, topStaticScope_);
public:
GlobalSharedContext(ExclusiveContext* cx,
Directives directives, Handle<StaticEvalObject*> staticEvalScope,
bool extraWarnings)
: SharedContext(cx, directives, extraWarnings),
staticEvalScope_(staticEvalScope)
{}
ObjectBox* toObjectBox() { return nullptr; }
HandleObject evalStaticScope() const { return staticEvalScope_; }
bool allowSyntax(AllowedSyntax allowed) const {
StaticScopeIter<CanGC> it(context, staticEvalScope_);
for (; !it.done(); it++) {
if (it.type() == StaticScopeIter<CanGC>::Function &&
!it.fun().isArrow())
@ -273,40 +282,6 @@ class GlobalSharedContext : public SharedContext
}
return false;
}
bool computeInWith() const {
for (StaticScopeIter<CanGC> it(context, topStaticScope_); !it.done(); it++) {
if (it.type() == StaticScopeIter<CanGC>::With)
return true;
}
return false;
}
public:
GlobalSharedContext(ExclusiveContext* cx,
Directives directives, Handle<ScopeObject*> topStaticScope,
bool extraWarnings)
: SharedContext(cx, directives, extraWarnings),
topStaticScope_(topStaticScope),
allowNewTarget_(computeAllowSyntax(AllowedSyntax::NewTarget)),
allowSuperProperty_(computeAllowSyntax(AllowedSyntax::SuperProperty)),
inWith_(computeInWith())
{}
ObjectBox* toObjectBox() override { return nullptr; }
HandleObject topStaticScope() const { return topStaticScope_; }
bool allowSyntax(AllowedSyntax allowSyntax) const override {
switch (allowSyntax) {
case AllowedSyntax::NewTarget:
// Any function supports new.target
return allowNewTarget_;
case AllowedSyntax::SuperProperty:
return allowSuperProperty_;
default:;
}
MOZ_CRASH("Unknown AllowedSyntax query");
}
bool inWith() const override { return inWith_; }
};
class FunctionBox : public ObjectBox, public SharedContext
@ -320,7 +295,7 @@ class FunctionBox : public ObjectBox, public SharedContext
uint16_t length;
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
bool inWith_:1; /* some enclosing scope is a with-statement */
bool inWith:1; /* some enclosing scope is a with-statement */
bool inGenexpLambda:1; /* lambda from generator expression */
bool hasDestructuringArgs:1; /* arguments list contains destructuring expression */
bool useAsm:1; /* see useAsmOrInsideUseAsm */
@ -338,7 +313,7 @@ class FunctionBox : public ObjectBox, public SharedContext
ParseContext<ParseHandler>* pc, Directives directives,
bool extraWarnings, GeneratorKind generatorKind);
ObjectBox* toObjectBox() override { return this; }
ObjectBox* toObjectBox() { return this; }
JSFunction* function() const { return &object->as<JSFunction>(); }
GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
@ -360,6 +335,7 @@ class FunctionBox : public ObjectBox, public SharedContext
bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; }
bool definitelyNeedsArgsObj() const { return funCxFlags.definitelyNeedsArgsObj; }
bool needsHomeObject() const { return funCxFlags.needsHomeObject; }
bool isDerivedClassConstructor() const { return funCxFlags.isDerivedClassConstructor; }
void setMightAliasLocals() { funCxFlags.mightAliasLocals = true; }
void setHasExtensibleScope() { funCxFlags.hasExtensibleScope = true; }
@ -369,6 +345,8 @@ class FunctionBox : public ObjectBox, public SharedContext
funCxFlags.definitelyNeedsArgsObj = true; }
void setNeedsHomeObject() { MOZ_ASSERT(function()->allowSuperProperty());
funCxFlags.needsHomeObject = true; }
void setDerivedClassConstructor() { MOZ_ASSERT(function()->isClassConstructor());
funCxFlags.isDerivedClassConstructor = true; }
bool hasDefaults() const {
return length != function()->nargs() - function()->hasRest();
@ -399,13 +377,9 @@ class FunctionBox : public ObjectBox, public SharedContext
isGenerator();
}
bool allowSyntax(AllowedSyntax allowed) const override {
bool allowSyntax(AllowedSyntax allowed) const {
return FunctionAllowsSyntax(function(), allowed);
}
bool inWith() const override {
return inWith_;
}
};
inline FunctionBox*

View File

@ -329,6 +329,7 @@ class SyntaxParseHandler
void setEndPosition(Node pn, Node oth) {}
void setEndPosition(Node pn, uint32_t end) {}
void setDerivedClassConstructor(Node pn) {}
void setPosition(Node pn, const TokenPos& pos) {}
TokenPos getPosition(Node pn) {

View File

@ -4,7 +4,6 @@ var g = newGlobal();
var g2 = newGlobal();
var dbg = new Debugger(g, g2);
var log = '';
var canary = 42;
dbg.onNewScript = function (evalScript) {
log += 'e';
@ -25,8 +24,5 @@ dbg.onDebuggerStatement = function (frame) {
};
assertEq(log, '');
var evalScope = g.evalReturningScope("canary = 'dead'; debugger; // nee", g2);
var evalScope = g.evalReturningScope("debugger; // nee", g2);
assertEq(log, 'ecbd');
assertEq(canary, 42);
assertEq(evalScope.canary, 'dead');

View File

@ -704,14 +704,13 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
scopeChain = fun->environment();
}
} else {
// For global scripts without a non-syntactic scope the scope
// For global scripts without a polluted global scope the scope
// chain is the script's global (Ion does not compile scripts
// with a non-syntactic global scope). Also note that it's
// invalid to resume into the prologue in this case because
// the prologue expects the scope chain in R1 for eval and
// global scripts.
// with a polluted global scope). Also note that it's invalid to
// resume into the prologue in this case because the prologue
// expects the scope chain in R1 for eval and global scripts.
MOZ_ASSERT(!script->isForEval());
MOZ_ASSERT(!script->hasNonSyntacticScope());
MOZ_ASSERT(!script->hasPollutedGlobalScope());
scopeChain = &(script->global());
}
}

View File

@ -20,7 +20,6 @@
#endif
#include "jit/SharedICHelpers.h"
#include "jit/VMFunctions.h"
#include "vm/ScopeObject.h"
#include "vm/TraceLogging.h"
#include "jsscriptinlines.h"
@ -129,7 +128,7 @@ BaselineCompiler::compile()
return Method_Error;
if (fun->isNamedLambda()) {
RootedObject declEnvObject(cx, DeclEnvObject::createTemplateObject(cx, fun, TenuredObject));
RootedObject declEnvObject(cx, DeclEnvObject::createTemplateObject(cx, fun, gc::TenuredHeap));
if (!declEnvObject)
return Method_Error;
templateScope->as<ScopeObject>().setEnclosingScope(declEnvObject);
@ -2063,7 +2062,7 @@ BaselineCompiler::emit_JSOP_IN()
bool
BaselineCompiler::emit_JSOP_GETGNAME()
{
if (script->hasNonSyntacticScope())
if (script->hasPollutedGlobalScope())
return emit_JSOP_GETNAME();
RootedPropertyName name(cx, script->getName(pc));
@ -2098,7 +2097,7 @@ BaselineCompiler::emit_JSOP_GETGNAME()
bool
BaselineCompiler::emit_JSOP_BINDGNAME()
{
if (!script->hasNonSyntacticScope()) {
if (!script->hasPollutedGlobalScope()) {
frame.push(ObjectValue(script->global()));
return true;
}
@ -2921,7 +2920,7 @@ BaselineCompiler::emit_JSOP_IMPLICITTHIS()
bool
BaselineCompiler::emit_JSOP_GIMPLICITTHIS()
{
if (!script->hasNonSyntacticScope()) {
if (!script->hasPollutedGlobalScope()) {
frame.push(UndefinedValue());
return true;
}

View File

@ -6133,7 +6133,7 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_
attached = true;
}
if (!attached && IsGlobalOp(JSOp(*pc)) && !script->hasNonSyntacticScope()) {
if (!attached && IsGlobalOp(JSOp(*pc)) && !script->hasPollutedGlobalScope()) {
if (!TryAttachGlobalNameAccessorStub(cx, script, pc, stub, scopeChain.as<GlobalObject>(),
name, &attached, &isTemporarilyUnoptimizable))
{
@ -6163,7 +6163,7 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_
if (attached)
return true;
if (IsGlobalOp(JSOp(*pc)) && !script->hasNonSyntacticScope()) {
if (IsGlobalOp(JSOp(*pc)) && !script->hasPollutedGlobalScope()) {
Handle<GlobalObject*> global = scopeChain.as<GlobalObject>();
if (!TryAttachGlobalNameValueStub(cx, script, pc, stub, global, name, &attached))
return false;

View File

@ -170,7 +170,7 @@ BytecodeAnalysis::init(TempAllocator& alloc, GSNCache& gsn)
case JSOP_GETGNAME:
case JSOP_SETGNAME:
case JSOP_STRICTSETGNAME:
if (script_->hasNonSyntacticScope())
if (script_->hasPollutedGlobalScope())
usesScopeChain_ = true;
break;

View File

@ -4686,7 +4686,7 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox* lir)
bailoutFrom(&bail, lir->snapshot());
}
typedef js::DeclEnvObject* (*NewDeclEnvObjectFn)(JSContext*, HandleFunction, NewObjectKind);
typedef js::DeclEnvObject* (*NewDeclEnvObjectFn)(JSContext*, HandleFunction, gc::InitialHeap);
static const VMFunction NewDeclEnvObjectInfo =
FunctionInfo<NewDeclEnvObjectFn>(DeclEnvObject::createTemplateObject);
@ -4700,7 +4700,7 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject* lir)
// If we have a template object, we can inline call object creation.
OutOfLineCode* ool = oolCallVM(NewDeclEnvObjectInfo, lir,
ArgList(ImmGCPtr(info.funMaybeLazy()), Imm32(GenericObject)),
ArgList(ImmGCPtr(info.funMaybeLazy()), Imm32(gc::DefaultHeap)),
StoreRegisterTo(objReg));
bool initContents = ShouldInitFixedSlots(lir, templateObj);

View File

@ -2173,12 +2173,12 @@ CheckScript(JSContext* cx, JSScript* script, bool osr)
return false;
}
if (script->hasNonSyntacticScope() && !script->functionNonDelazifying()) {
// Support functions with a non-syntactic global scope but not other
if (script->hasPollutedGlobalScope() && !script->functionNonDelazifying()) {
// Support functions with a polluted global scope but not other
// scripts. For global scripts, IonBuilder currently uses the global
// object as scope chain, this is not valid when the script has a
// non-syntactic global scope.
TrackAndSpewIonAbort(cx, script, "has non-syntactic global scope");
// polluted global scope.
TrackAndSpewIonAbort(cx, script, "has polluted global scope");
return false;
}

View File

@ -618,7 +618,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
type = MIRType_Undefined;
break;
case JSOP_GIMPLICITTHIS:
if (!script()->hasNonSyntacticScope())
if (!script()->hasPollutedGlobalScope())
type = MIRType_Undefined;
break;
case JSOP_NULL:
@ -1182,10 +1182,10 @@ IonBuilder::initScopeChain(MDefinition* callee)
return false;
}
} else {
// For global scripts without a non-syntactic global scope, the scope
// chain is the global object.
// For global scripts without a polluted global scope, the scope chain
// is the global object.
MOZ_ASSERT(!script()->isForEval());
MOZ_ASSERT(!script()->hasNonSyntacticScope());
MOZ_ASSERT(!script()->hasPollutedGlobalScope());
scope = constant(ObjectValue(script()->global()));
}
@ -1800,7 +1800,7 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_GETGNAME:
{
PropertyName* name = info().getAtom(pc)->asPropertyName();
if (!script()->hasNonSyntacticScope())
if (!script()->hasPollutedGlobalScope())
return jsop_getgname(name);
return jsop_getname(name);
}
@ -1809,7 +1809,7 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_STRICTSETGNAME:
{
PropertyName* name = info().getAtom(pc)->asPropertyName();
if (script()->hasNonSyntacticScope())
if (script()->hasPollutedGlobalScope())
return jsop_setprop(name);
JSObject* obj = &script()->global();
return setStaticName(obj, name);
@ -1828,7 +1828,7 @@ IonBuilder::inspectOpcode(JSOp op)
}
case JSOP_BINDGNAME:
if (!script()->hasNonSyntacticScope())
if (!script()->hasPollutedGlobalScope())
return pushConstant(ObjectValue(script()->global()));
// Fall through to JSOP_BINDNAME
case JSOP_BINDNAME:
@ -1975,7 +1975,7 @@ IonBuilder::inspectOpcode(JSOp op)
return jsop_debugger();
case JSOP_GIMPLICITTHIS:
if (!script()->hasNonSyntacticScope())
if (!script()->hasPollutedGlobalScope())
return pushConstant(UndefinedValue());
// Just fall through to the unsupported bytecode case.
@ -7613,7 +7613,7 @@ bool
IonBuilder::jsop_getname(PropertyName* name)
{
MDefinition* object;
if (IsGlobalOp(JSOp(*pc)) && !script()->hasNonSyntacticScope()) {
if (IsGlobalOp(JSOp(*pc)) && !script()->hasPollutedGlobalScope()) {
MInstruction* global = constant(ObjectValue(script()->global()));
object = global;
} else {

View File

@ -2553,7 +2553,7 @@ InlineFrameIterator::computeScopeChain(Value scopeChainValue, MaybeReadFallback&
// Ion does not handle non-function scripts that have anything other than
// the global on their scope chain.
MOZ_ASSERT(!script()->isForEval());
MOZ_ASSERT(!script()->hasNonSyntacticScope());
MOZ_ASSERT(!script()->hasPollutedGlobalScope());
return &script()->global();
}

View File

@ -103,6 +103,7 @@ MSG_DEF(JSMSG_INVALID_ARG_TYPE, 3, JSEXN_TYPEERR, "Invalid type: {0} can'
MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not an object or null")
MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|")
MSG_DEF(JSMSG_DISABLED_DERIVED_CLASS, 1, JSEXN_INTERNALERR, "{0} temporarily disallowed in derived class constructors")
// JSON
MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")

View File

@ -11,6 +11,8 @@ BEGIN_TEST(testJSEvaluateScript)
JS::RootedObject obj(cx, JS_NewPlainObject(cx));
CHECK(obj);
CHECK(JS::RuntimeOptionsRef(cx).varObjFix());
static const char16_t src[] = MOZ_UTF16("var x = 5;");
JS::RootedValue retval(cx);
@ -22,10 +24,26 @@ BEGIN_TEST(testJSEvaluateScript)
bool hasProp = true;
CHECK(JS_AlreadyHasOwnProperty(cx, obj, "x", &hasProp));
CHECK(hasProp);
CHECK(!hasProp);
hasProp = false;
CHECK(JS_HasProperty(cx, global, "x", &hasProp));
CHECK(hasProp);
// Now do the same thing, but without JSOPTION_VAROBJFIX
JS::RuntimeOptionsRef(cx).setVarObjFix(false);
static const char16_t src2[] = MOZ_UTF16("var y = 5;");
CHECK(JS::Evaluate(cx, scopeChain, opts.setFileAndLine(__FILE__, __LINE__),
src2, ArrayLength(src2) - 1, &retval));
hasProp = false;
CHECK(JS_AlreadyHasOwnProperty(cx, obj, "y", &hasProp));
CHECK(hasProp);
hasProp = true;
CHECK(JS_AlreadyHasOwnProperty(cx, global, "y", &hasProp));
CHECK(!hasProp);
return true;

View File

@ -285,6 +285,7 @@ class JSAPITest
return nullptr;
JS_SetErrorReporter(rt, &reportError);
setNativeStackQuota(rt);
JS::RuntimeOptionsRef(rt).setVarObjFix(true);
return rt;
}

View File

@ -3299,32 +3299,12 @@ JS::GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id
}
static bool
CreateNonSyntacticScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
MutableHandleObject dynamicScopeObj,
MutableHandle<ScopeObject*> staticScopeObj)
CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
MutableHandleObject dynamicScopeObj,
MutableHandleObject staticScopeObj)
{
if (!js::CreateScopeObjectsForScopeChain(cx, scopeChain, cx->global(), dynamicScopeObj))
return false;
if (scopeChain.empty()) {
staticScopeObj.set(nullptr);
} else {
staticScopeObj.set(StaticNonSyntacticScopeObjects::create(cx, nullptr));
if (!staticScopeObj)
return false;
// The XPConnect subscript loader, which may pass in its own dynamic
// scopes to load scripts in, expects the dynamic scope chain to be
// the holder of "var" declarations. In SpiderMonkey, such objects are
// called "qualified varobjs", the "qualified" part meaning the
// declaration was qualified by "var". There is only sadness.
//
// See JSObject::isQualifiedVarObj.
if (!dynamicScopeObj->setQualifiedVarObj(cx))
return false;
}
return true;
return js::CreateScopeObjectsForScopeChain(cx, scopeChain, cx->global(),
dynamicScopeObj, staticScopeObj);
}
static bool
@ -3335,23 +3315,11 @@ IsFunctionCloneable(HandleFunction fun, HandleObject dynamicScope)
// If a function was compiled to be lexically nested inside some other
// script, we cannot clone it without breaking the compiler's assumptions.
if (JSObject* scope = fun->nonLazyScript()->enclosingStaticScope()) {
// If the script already deals with a non-syntactic scope, we can clone
// it.
if (scope->is<StaticNonSyntacticScopeObjects>())
return true;
// 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;
}
// Any other enclosing static scope (e.g., function, block) cannot be
// cloned.
JSObject* scope = fun->nonLazyScript()->enclosingStaticScope();
if (scope && (!scope->is<StaticEvalObject>() ||
scope->as<StaticEvalObject>().isDirect() ||
scope->as<StaticEvalObject>().isStrict()))
{
return false;
}
@ -3359,8 +3327,7 @@ IsFunctionCloneable(HandleFunction fun, HandleObject dynamicScope)
}
static JSObject*
CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScope,
Handle<ScopeObject*> staticScope)
CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScope)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
@ -3397,21 +3364,7 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScop
return nullptr;
}
if (CanReuseScriptForClone(cx->compartment(), fun, dynamicScope)) {
// If the script is to be reused, either the script can already handle
// non-syntactic scopes, or there is no new static scope.
#ifdef DEBUG
// Fail here if we OOM during debug asserting.
// CloneFunctionReuseScript will delazify the script anyways, so we
// are not creating an extra failure condition for DEBUG builds.
if (!fun->getOrCreateScript(cx))
return nullptr;
MOZ_ASSERT(!staticScope || fun->nonLazyScript()->hasNonSyntacticScope());
#endif
return CloneFunctionReuseScript(cx, fun, dynamicScope, fun->getAllocKind());
}
return CloneFunctionAndScript(cx, fun, dynamicScope, staticScope, fun->getAllocKind());
return CloneFunctionObject(cx, fun, dynamicScope, fun->getAllocKind());
}
namespace JS {
@ -3419,18 +3372,18 @@ namespace JS {
JS_PUBLIC_API(JSObject*)
CloneFunctionObject(JSContext* cx, JS::Handle<JSObject*> funobj)
{
return CloneFunctionObject(cx, funobj, cx->global(), /* staticScope = */ nullptr);
return CloneFunctionObject(cx, funobj, cx->global());
}
extern JS_PUBLIC_API(JSObject*)
CloneFunctionObject(JSContext* cx, HandleObject funobj, AutoObjectVector& scopeChain)
{
RootedObject dynamicScope(cx);
Rooted<ScopeObject*> staticScope(cx);
if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScope, &staticScope))
RootedObject unusedStaticScope(cx);
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScope, &unusedStaticScope))
return nullptr;
return CloneFunctionObject(cx, funobj, dynamicScope, staticScope);
return CloneFunctionObject(cx, funobj, dynamicScope);
}
} // namespace JS
@ -3900,40 +3853,31 @@ JS::CompileOptions::CompileOptions(JSContext* cx, JSVersion version)
asmJSOption = cx->runtime()->options().asmJS();
}
enum SyntacticScopeOption { HasSyntacticScope, HasNonSyntacticScope };
static bool
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOption scopeOption,
SourceBufferHolder& srcBuf, MutableHandleScript script)
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, MutableHandleScript script)
{
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
AutoLastFrameCheck lfc(cx);
Rooted<ScopeObject*> staticScope(cx);
if (scopeOption == HasNonSyntacticScope) {
staticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr);
if (!staticScope)
return false;
}
script.set(frontend::CompileScript(cx, &cx->tempLifoAlloc(), cx->global(),
staticScope, nullptr, options, srcBuf));
nullptr, nullptr, options, srcBuf));
return !!script;
}
static bool
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOption scopeOption,
const char16_t* chars, size_t length, MutableHandleScript script)
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, MutableHandleScript script)
{
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
return ::Compile(cx, options, scopeOption, srcBuf, script);
return Compile(cx, options, srcBuf, script);
}
static bool
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOption scopeOption,
const char* bytes, size_t length, MutableHandleScript script)
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* bytes, size_t length, MutableHandleScript script)
{
mozilla::UniquePtr<char16_t, JS::FreePolicy> chars;
if (options.utf8)
@ -3943,101 +3887,30 @@ Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOpti
if (!chars)
return false;
return ::Compile(cx, options, scopeOption, chars.get(), length, script);
return Compile(cx, options, chars.get(), length, script);
}
static bool
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOption scopeOption,
FILE* fp, MutableHandleScript script)
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options, FILE* fp,
MutableHandleScript script)
{
FileContents buffer(cx);
if (!ReadCompleteFile(cx, fp, buffer))
return false;
return ::Compile(cx, options, scopeOption, buffer.begin(), buffer.length(), script);
return Compile(cx, options, buffer.begin(), buffer.length(), script);
}
static bool
Compile(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, SyntacticScopeOption scopeOption,
const char* filename, MutableHandleScript script)
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, const char* filename,
MutableHandleScript script)
{
AutoFile file;
if (!file.open(cx, filename))
return false;
CompileOptions options(cx, optionsArg);
options.setFileAndLine(filename, 1);
return ::Compile(cx, options, scopeOption, file.fp(), script);
}
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasSyntacticScope, srcBuf, script);
}
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* bytes, size_t length, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasSyntacticScope, bytes, length, script);
}
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasSyntacticScope, chars, length, script);
}
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
FILE* file, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasSyntacticScope, file, script);
}
bool
JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* filename, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasSyntacticScope, filename, script);
}
bool
JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasNonSyntacticScope, srcBuf, script);
}
bool
JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* bytes, size_t length, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasNonSyntacticScope, bytes, length, script);
}
bool
JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length,
JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasNonSyntacticScope, chars, length, script);
}
bool
JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
FILE* file, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasNonSyntacticScope, file, script);
}
bool
JS::CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* filename, JS::MutableHandleScript script)
{
return ::Compile(cx, options, HasNonSyntacticScope, filename, script);
return Compile(cx, options, file.fp(), script);
}
JS_PUBLIC_API(bool)
@ -4220,13 +4093,13 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
if (!fun)
return false;
// Make sure the static scope chain matches up when we have a
// non-syntactic scope.
MOZ_ASSERT_IF(!enclosingDynamicScope->is<GlobalObject>(),
HasNonSyntacticStaticScopeChain(enclosingStaticScope));
// Make sure to handle cases when we have a polluted scopechain.
CompileOptions options(cx, optionsArg);
if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingStaticScope))
if (!enclosingDynamicScope->is<GlobalObject>())
options.setHasPollutedScope(true);
if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf,
enclosingStaticScope))
return false;
return true;
@ -4239,8 +4112,8 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& scopeChain,
SourceBufferHolder& srcBuf, MutableHandleFunction fun)
{
RootedObject dynamicScopeObj(cx);
Rooted<ScopeObject*> staticScopeObj(cx);
if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScopeObj, &staticScopeObj))
RootedObject staticScopeObj(cx);
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScopeObj, &staticScopeObj))
return false;
return CompileFunction(cx, options, name, nargs, argnames,
@ -4314,34 +4187,33 @@ JS_DecompileFunctionBody(JSContext* cx, HandleFunction fun, unsigned indent)
}
MOZ_NEVER_INLINE static bool
ExecuteScript(JSContext* cx, HandleObject scope, HandleScript script, jsval* rval)
ExecuteScript(JSContext* cx, HandleObject obj, HandleScript scriptArg, jsval* rval)
{
RootedScript script(cx, scriptArg);
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, scope, script);
MOZ_ASSERT_IF(!scope->is<GlobalObject>(), script->hasNonSyntacticScope());
assertSameCompartment(cx, obj, scriptArg);
if (!script->hasPollutedGlobalScope() && !obj->is<GlobalObject>()) {
script = CloneScript(cx, nullptr, nullptr, script, HasPollutedGlobalScope);
if (!script)
return false;
js::Debugger::onNewScript(cx, script);
}
AutoLastFrameCheck lfc(cx);
return Execute(cx, script, *scope, rval);
return Execute(cx, script, *obj, rval);
}
static bool
ExecuteScript(JSContext* cx, AutoObjectVector& scopeChain, HandleScript scriptArg, jsval* rval)
{
RootedObject dynamicScope(cx);
Rooted<ScopeObject*> staticScope(cx);
if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScope, &staticScope))
RootedObject unusedStaticScope(cx);
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScope, &unusedStaticScope))
return false;
RootedScript script(cx, scriptArg);
if (!script->hasNonSyntacticScope() && !dynamicScope->is<GlobalObject>()) {
script = CloneGlobalScript(cx, staticScope, script);
if (!script)
return false;
js::Debugger::onNewScript(cx, script);
}
return ExecuteScript(cx, dynamicScope, script, rval);
return ExecuteScript(cx, dynamicScope, scriptArg, rval);
}
MOZ_NEVER_INLINE JS_PUBLIC_API(bool)
@ -4375,7 +4247,7 @@ JS::CloneAndExecuteScript(JSContext* cx, HandleScript scriptArg)
CHECK_REQUEST(cx);
RootedScript script(cx, scriptArg);
if (script->compartment() != cx->compartment()) {
script = CloneGlobalScript(cx, /* enclosingScope = */ nullptr, script);
script = CloneScript(cx, nullptr, nullptr, script);
if (!script)
return false;
@ -4387,8 +4259,7 @@ JS::CloneAndExecuteScript(JSContext* cx, HandleScript scriptArg)
static const unsigned LARGE_SCRIPT_LENGTH = 500*1024;
static bool
Evaluate(JSContext* cx, HandleObject scope, Handle<ScopeObject*> staticScope,
const ReadOnlyCompileOptions& optionsArg,
Evaluate(JSContext* cx, HandleObject scope, const ReadOnlyCompileOptions& optionsArg,
SourceBufferHolder& srcBuf, MutableHandleValue rval)
{
CompileOptions options(cx, optionsArg);
@ -4399,14 +4270,12 @@ Evaluate(JSContext* cx, HandleObject scope, Handle<ScopeObject*> staticScope,
AutoLastFrameCheck lfc(cx);
MOZ_ASSERT_IF(!scope->is<GlobalObject>(), HasNonSyntacticStaticScopeChain(staticScope));
options.setHasPollutedScope(!scope->is<GlobalObject>());
options.setIsRunOnce(true);
SourceCompressionTask sct(cx);
RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scope, staticScope,
/* evalCaller = */ nullptr, options,
srcBuf, /* source = */ nullptr, 0, &sct));
scope, nullptr, nullptr, options,
srcBuf, nullptr, 0, &sct));
if (!script)
return false;
@ -4436,10 +4305,10 @@ Evaluate(JSContext* cx, AutoObjectVector& scopeChain, const ReadOnlyCompileOptio
SourceBufferHolder& srcBuf, MutableHandleValue rval)
{
RootedObject dynamicScope(cx);
Rooted<ScopeObject*> staticScope(cx);
if (!CreateNonSyntacticScopeChain(cx, scopeChain, &dynamicScope, &staticScope))
RootedObject unusedStaticScope(cx);
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScope, &unusedStaticScope))
return false;
return ::Evaluate(cx, dynamicScope, staticScope, optionsArg, srcBuf, rval);
return ::Evaluate(cx, dynamicScope, optionsArg, srcBuf, rval);
}
static bool
@ -4447,7 +4316,7 @@ Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
const char16_t* chars, size_t length, MutableHandleValue rval)
{
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
return ::Evaluate(cx, cx->global(), nullptr, optionsArg, srcBuf, rval);
return ::Evaluate(cx, cx->global(), optionsArg, srcBuf, rval);
}
extern JS_PUBLIC_API(bool)
@ -4463,7 +4332,7 @@ JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options,
return false;
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::GiveOwnership);
bool ok = ::Evaluate(cx, cx->global(), nullptr, options, srcBuf, rval);
bool ok = ::Evaluate(cx, cx->global(), options, srcBuf, rval);
return ok;
}
@ -4487,7 +4356,7 @@ JS_PUBLIC_API(bool)
JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
SourceBufferHolder& srcBuf, MutableHandleValue rval)
{
return ::Evaluate(cx, cx->global(), nullptr, optionsArg, srcBuf, rval);
return ::Evaluate(cx, cx->global(), optionsArg, srcBuf, rval);
}
JS_PUBLIC_API(bool)

View File

@ -1186,7 +1186,8 @@ class JS_PUBLIC_API(RuntimeOptions) {
asyncStack_(true),
werror_(false),
strictMode_(false),
extraWarnings_(false)
extraWarnings_(false),
varObjFix_(false)
{
}
@ -1268,6 +1269,16 @@ class JS_PUBLIC_API(RuntimeOptions) {
return *this;
}
bool varObjFix() const { return varObjFix_; }
RuntimeOptions& setVarObjFix(bool flag) {
varObjFix_ = flag;
return *this;
}
RuntimeOptions& toggleVarObjFix() {
varObjFix_ = !varObjFix_;
return *this;
}
private:
bool baseline_ : 1;
bool ion_ : 1;
@ -1278,6 +1289,7 @@ class JS_PUBLIC_API(RuntimeOptions) {
bool werror_ : 1;
bool strictMode_ : 1;
bool extraWarnings_ : 1;
bool varObjFix_ : 1;
};
JS_PUBLIC_API(RuntimeOptions&)
@ -3453,6 +3465,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
utf8(false),
lineno(1),
column(0),
hasPollutedGlobalScope(false),
isRunOnce(false),
forEval(false),
noScriptRval(false),
@ -3492,6 +3505,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
bool utf8;
unsigned lineno;
unsigned column;
bool hasPollutedGlobalScope;
// isRunOnce only applies to non-function scripts.
bool isRunOnce;
bool forEval;
@ -3584,6 +3598,7 @@ class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions
}
OwningCompileOptions& setUTF8(bool u) { utf8 = u; return *this; }
OwningCompileOptions& setColumn(unsigned c) { column = c; return *this; }
OwningCompileOptions& setHasPollutedScope(bool p) { hasPollutedGlobalScope = p; return *this; }
OwningCompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; }
OwningCompileOptions& setForEval(bool eval) { forEval = eval; return *this; }
OwningCompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
@ -3667,6 +3682,7 @@ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOpti
}
CompileOptions& setUTF8(bool u) { utf8 = u; return *this; }
CompileOptions& setColumn(unsigned c) { column = c; return *this; }
CompileOptions& setHasPollutedScope(bool p) { hasPollutedGlobalScope = p; return *this; }
CompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; }
CompileOptions& setForEval(bool eval) { forEval = eval; return *this; }
CompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
@ -3710,32 +3726,12 @@ Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
FILE* file, JS::MutableHandleScript script);
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, FILE* file,
JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* filename, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* bytes, size_t length, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
FILE* file, JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* filename, JS::MutableHandleScript script);
Compile(JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename,
JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CanCompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length);
@ -3821,8 +3817,24 @@ JS_DecompileFunctionBody(JSContext* cx, JS::Handle<JSFunction*> fun, unsigned in
* latter case, the first object in the provided list is used, unless the list
* is empty, in which case the global is used.
*
* Why a runtime option? The alternative is to add APIs duplicating those
* for the other value of flags, and that doesn't seem worth the code bloat
* Using a non-global object as the variables object is problematic: in this
* case, variables created by 'var x = 0', e.g., go in that object, but
* variables created by assignment to an unbound id, 'x = 0', go in the global.
*
* ECMA requires that "global code" be executed with the variables object equal
* to the global object. But these JS API entry points provide freedom to
* execute code against a "sub-global", i.e., a parented or scoped object, in
* which case the variables object will differ from the global, resulting in
* confusing and non-ECMA explicit vs. implicit variable creation.
*
* Caveat embedders: unless you already depend on this buggy variables object
* binding behavior, you should call RuntimeOptionsRef(rt).setVarObjFix(true)
* for each context in the application, if you use the versions of
* JS_ExecuteScript and JS::Evaluate that take a scope chain argument, or may
* ever use them in the future.
*
* Why a runtime option? The alternative is to add APIs duplicating those below
* for the other value of varobjfix, and that doesn't seem worth the code bloat
* cost. Such new entry points would probably have less obvious names, too, so
* would not tend to be used. The RuntimeOptionsRef adjustment, OTOH, can be
* more easily hacked into existing code that does not depend on the bug; such

View File

@ -35,7 +35,6 @@
#include "jit/JitFrameIterator.h"
#include "js/CallNonGenericMethod.h"
#include "js/Proxy.h"
#include "vm/Debugger.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
#include "vm/Shape.h"
@ -525,7 +524,7 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope, Han
HasSingletonType = 0x8
};
/* NB: Keep this in sync with CloneInnerInterpretedFunction. */
/* NB: Keep this in sync with CloneFunctionAndScript. */
RootedAtom atom(xdr->cx());
uint32_t firstword = 0; /* bitmask of FirstWordFlag */
uint32_t flagsword = 0; /* word for argument count and fun->flags */
@ -616,9 +615,10 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope, Han
fun->setFlags(uint16_t(flagsword));
fun->initAtom(atom);
if (firstword & IsLazy) {
MOZ_ASSERT(fun->lazyScript() == lazy);
fun->initLazyScript(lazy);
} else {
MOZ_ASSERT(fun->nonLazyScript() == script);
fun->initScript(script);
script->setFunction(fun);
MOZ_ASSERT(fun->nargs() == script->bindings.numArgs());
}
@ -637,6 +637,44 @@ js::XDRInterpretedFunction(XDRState<XDR_ENCODE>*, HandleObject, HandleScript, Mu
template bool
js::XDRInterpretedFunction(XDRState<XDR_DECODE>*, HandleObject, HandleScript, MutableHandleFunction);
JSObject*
js::CloneFunctionAndScript(JSContext* cx, HandleObject enclosingScope, HandleFunction srcFun,
PollutedGlobalScopeOption polluted)
{
/* NB: Keep this in sync with XDRInterpretedFunction. */
RootedObject cloneProto(cx);
if (srcFun->isStarGenerator()) {
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
if (!cloneProto)
return nullptr;
}
gc::AllocKind allocKind = srcFun->getAllocKind();
RootedFunction clone(cx, NewFunctionWithProto(cx, nullptr, 0,
JSFunction::INTERPRETED, nullptr, nullptr,
cloneProto, allocKind, TenuredObject));
if (!clone)
return nullptr;
JSScript::AutoDelazify srcScript(cx, srcFun);
if (!srcScript)
return nullptr;
RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, clone, srcScript, polluted));
if (!clonedScript)
return nullptr;
clone->setArgCount(srcFun->nargs());
clone->setFlags(srcFun->flags());
clone->initAtom(srcFun->displayAtom());
clone->initScript(clonedScript);
clonedScript->setFunction(clone);
if (!JSFunction::setTypeForScriptedFunction(cx, clone))
return nullptr;
RootedScript cloneScript(cx, clone->nonLazyScript());
return clone;
}
/*
* [[HasInstance]] internal method for Function objects: fetch the .prototype
* property of its 'this' parameter, and walks the prototype chain of v (only
@ -790,7 +828,7 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
/*
* The default 'new' group of Function.prototype is required by type
* inference to have unknown properties, to simplify handling of e.g.
* NewFunctionClone.
* CloneFunctionObject.
*/
if (!JSObject::setNewGroupUnknown(cx, &JSFunction::class_, functionProto))
return nullptr;
@ -1385,13 +1423,16 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
if (script) {
RootedObject enclosingScope(cx, lazy->enclosingScope());
RootedScript clonedScript(cx, CloneScriptIntoFunction(cx, enclosingScope, fun, script));
RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script));
if (!clonedScript)
return false;
clonedScript->setSourceObject(lazy->sourceObject());
fun->initAtom(script->functionNonDelazifying()->displayAtom());
clonedScript->setFunction(fun);
fun->setUnlazifiedScript(clonedScript);
if (!lazy->maybeScript())
lazy->initScript(clonedScript);
@ -1978,20 +2019,6 @@ js::NewScriptedFunction(ExclusiveContext* cx, unsigned nargs,
atom, nullptr, allocKind, newKind);
}
#ifdef DEBUG
static bool
NewFunctionScopeIsWellFormed(ExclusiveContext* cx, HandleObject parent)
{
// Assert that the parent is null, global, or a debug scope proxy. All
// other cases of polluting global scope behavior are handled by
// ScopeObjects (viz. non-syntactic DynamicWithObject and
// NonSyntacticVariablesObject).
RootedObject realParent(cx, SkipScopeParent(parent));
return !realParent || realParent == cx->global() ||
realParent->is<DebugScopeObject>();
}
#endif
JSFunction*
js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
unsigned nargs, JSFunction::Flags flags, HandleObject enclosingDynamicScope,
@ -2001,7 +2028,6 @@ js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
{
MOZ_ASSERT(allocKind == AllocKind::FUNCTION || allocKind == AllocKind::FUNCTION_EXTENDED);
MOZ_ASSERT_IF(native, !enclosingDynamicScope);
MOZ_ASSERT(NewFunctionScopeIsWellFormed(cx, enclosingDynamicScope));
RootedObject funobj(cx);
// Don't mark asm.js module functions as singleton since they are
@ -2009,6 +2035,17 @@ js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
// isSingleton implies isInterpreted.
if (native && !IsAsmJSModuleNative(native))
newKind = SingletonObject;
#ifdef DEBUG
RootedObject nonScopeParent(cx, SkipScopeParent(enclosingDynamicScope));
// We'd like to assert that nonScopeParent is null-or-global, but
// js::ExecuteInGlobalAndReturnScope and debugger eval bits mess that up.
// Assert that it's one of those or a debug scope proxy or the unqualified
// var obj, since it should still be ok to parent to the global in that
// case.
MOZ_ASSERT(!nonScopeParent || nonScopeParent == cx->global() ||
nonScopeParent->is<DebugScopeObject>() ||
nonScopeParent->isUnqualifiedVarObj());
#endif
funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, allocKind,
newKind);
if (!funobj)
@ -2042,8 +2079,8 @@ js::NewFunctionWithProto(ExclusiveContext* cx, Native native,
}
bool
js::CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun,
HandleObject newParent)
js::CloneFunctionObjectUseSameScript(JSCompartment* compartment, HandleFunction fun,
HandleObject newParent)
{
if (compartment != fun->compartment() ||
fun->isSingleton() ||
@ -2064,36 +2101,75 @@ js::CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun,
return true;
// We need to clone the script if we're interpreted and not already marked
// as having a non-syntactic scope. If we're lazy, go ahead and clone the
// script; see the big comment at the end of CopyScriptInternal for the
// explanation of what's going on there.
// as having a polluted scope. If we're lazy, go ahead and clone the
// script; see the big comment at the end of CloneScript for the explanation
// of what's going on there.
return !fun->isInterpreted() ||
(fun->hasScript() && fun->nonLazyScript()->hasNonSyntacticScope());
(fun->hasScript() && fun->nonLazyScript()->hasPollutedGlobalScope());
}
static inline JSFunction*
NewFunctionClone(JSContext* cx, HandleFunction fun, NewObjectKind newKind,
gc::AllocKind allocKind, HandleObject proto)
JSFunction*
js::CloneFunctionObject(JSContext* cx, HandleFunction fun, HandleObject parent,
gc::AllocKind allocKind,
NewObjectKind newKindArg /* = GenericObject */,
HandleObject proto)
{
MOZ_ASSERT(parent);
MOZ_ASSERT(!fun->isBoundFunction());
bool useSameScript = CloneFunctionObjectUseSameScript(cx->compartment(), fun, parent);
NewObjectKind newKind = useSameScript ? newKindArg : SingletonObject;
RootedObject cloneProto(cx, proto);
if (!proto && fun->isStarGenerator()) {
if (!cloneProto && fun->isStarGenerator()) {
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
if (!cloneProto)
return nullptr;
}
#ifdef DEBUG
RootedObject realParent(cx, SkipScopeParent(parent));
// We'd like to assert that realParent is null-or-global, but
// js::ExecuteInGlobalAndReturnScope and debugger eval bits mess that up.
// Assert that it's one of those or a debug scope proxy or the unqualified
// var obj, since it should still be ok to parent to the global in that
// case.
MOZ_ASSERT(!realParent || realParent == cx->global() ||
realParent->is<DebugScopeObject>() ||
realParent->isUnqualifiedVarObj());
#endif
JSObject* cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto,
allocKind, newKind);
if (!cloneobj)
return nullptr;
RootedFunction clone(cx, &cloneobj->as<JSFunction>());
JSScript::AutoDelazify funScript(cx);
if (!useSameScript && fun->isInterpretedLazy()) {
funScript = fun;
if (!funScript)
return nullptr;
}
MOZ_ASSERT(useSameScript || !fun->isInterpretedLazy());
uint16_t flags = fun->flags() & ~JSFunction::EXTENDED;
if (allocKind == AllocKind::FUNCTION_EXTENDED)
flags |= JSFunction::EXTENDED;
clone->setArgCount(fun->nargs());
clone->setFlags(flags);
if (fun->hasScript()) {
clone->initScript(fun->nonLazyScript());
clone->initEnvironment(parent);
} else if (fun->isInterpretedLazy()) {
MOZ_ASSERT(fun->compartment() == clone->compartment());
MOZ_ASSERT(useSameScript);
LazyScript* lazy = fun->lazyScriptOrNull();
clone->initLazyScript(lazy);
clone->initEnvironment(parent);
} else {
clone->initNative(fun->native(), fun->jitInfo());
}
clone->initAtom(fun->displayAtom());
if (allocKind == AllocKind::FUNCTION_EXTENDED) {
@ -2105,97 +2181,34 @@ NewFunctionClone(JSContext* cx, HandleFunction fun, NewObjectKind newKind,
}
}
return clone;
}
JSFunction*
js::CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent,
gc::AllocKind allocKind /* = FUNCTION */ ,
NewObjectKind newKind /* = GenericObject */,
HandleObject proto /* = nullptr */)
{
MOZ_ASSERT(NewFunctionScopeIsWellFormed(cx, parent));
MOZ_ASSERT(!fun->isBoundFunction());
MOZ_ASSERT(CanReuseScriptForClone(cx->compartment(), fun, parent));
RootedFunction clone(cx, NewFunctionClone(cx, fun, newKind, allocKind, proto));
if (!clone)
return nullptr;
if (fun->hasScript()) {
clone->initScript(fun->nonLazyScript());
clone->initEnvironment(parent);
} else if (fun->isInterpretedLazy()) {
MOZ_ASSERT(fun->compartment() == clone->compartment());
LazyScript* lazy = fun->lazyScriptOrNull();
clone->initLazyScript(lazy);
clone->initEnvironment(parent);
} else {
clone->initNative(fun->native(), fun->jitInfo());
if (useSameScript) {
/*
* Clone the function, reusing its script. We can use the same group as
* the original function provided that its prototype is correct.
*/
if (fun->getProto() == clone->getProto())
clone->setGroup(fun->group());
return clone;
}
RootedFunction cloneRoot(cx, clone);
/*
* Clone the function, reusing its script. We can use the same group as
* the original function provided that its prototype is correct.
* Across compartments or if we have to introduce a polluted scope we have
* to clone the script for interpreted functions. Cross-compartment cloning
* only happens via JSAPI (JS::CloneFunctionObject) which dynamically
* ensures that 'script' has no enclosing lexical scope (only the global
* scope or other non-lexical scope).
*/
if (fun->getProto() == clone->getProto())
clone->setGroup(fun->group());
return clone;
}
JSFunction*
js::CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent,
HandleObject newStaticScope,
gc::AllocKind allocKind /* = FUNCTION */,
HandleObject proto /* = nullptr */)
{
MOZ_ASSERT(NewFunctionScopeIsWellFormed(cx, parent));
MOZ_ASSERT(!fun->isBoundFunction());
RootedFunction clone(cx, NewFunctionClone(cx, fun, SingletonObject, allocKind, proto));
if (!clone)
PollutedGlobalScopeOption globalScopeOption = parent->is<GlobalObject>() ?
HasCleanGlobalScope : HasPollutedGlobalScope;
if (cloneRoot->isInterpreted() &&
!CloneFunctionScript(cx, fun, cloneRoot, globalScopeOption, newKindArg))
{
return nullptr;
if (fun->hasScript()) {
clone->initScript(nullptr);
clone->initEnvironment(parent);
} else {
clone->initNative(fun->native(), fun->jitInfo());
}
/*
* Across compartments or if we have to introduce a non-syntactic scope we
* have to clone the script for interpreted functions. Cross-compartment
* cloning only happens via JSAPI (JS::CloneFunctionObject) which
* dynamically ensures that 'script' has no enclosing lexical scope (only
* the global scope or other non-lexical scope).
*/
#ifdef DEBUG
RootedObject terminatingScope(cx, parent);
while (IsSyntacticScope(terminatingScope))
terminatingScope = terminatingScope->enclosingScope();
MOZ_ASSERT_IF(!terminatingScope->is<GlobalObject>(),
HasNonSyntacticStaticScopeChain(newStaticScope));
#endif
if (clone->isInterpreted()) {
JSScript::AutoDelazify funScript(cx);
funScript = fun;
if (!funScript)
return nullptr;
RootedScript script(cx, fun->nonLazyScript());
MOZ_ASSERT(script->compartment() == fun->compartment());
MOZ_ASSERT(cx->compartment() == clone->compartment(),
"Otherwise we could relazify clone below!");
RootedScript clonedScript(cx, CloneScriptIntoFunction(cx, newStaticScope, clone, script));
if (!clonedScript)
return nullptr;
Debugger::onNewScript(cx, clonedScript);
}
return clone;
return cloneRoot;
}
/*

View File

@ -633,20 +633,14 @@ class FunctionExtended : public JSFunction
};
extern bool
CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun, HandleObject newParent);
CloneFunctionObjectUseSameScript(JSCompartment* compartment, HandleFunction fun,
HandleObject newParent);
extern JSFunction*
CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject parent,
gc::AllocKind kind = gc::AllocKind::FUNCTION,
NewObjectKind newKindArg = GenericObject,
HandleObject proto = nullptr);
// Functions whose scripts are cloned are always given singleton types.
extern JSFunction*
CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent,
HandleObject newStaticScope,
gc::AllocKind kind = gc::AllocKind::FUNCTION,
HandleObject proto = nullptr);
CloneFunctionObject(JSContext* cx, HandleFunction fun, HandleObject parent,
gc::AllocKind kind = gc::AllocKind::FUNCTION,
NewObjectKind newKindArg = GenericObject,
HandleObject proto = nullptr);
extern bool
FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart,
@ -708,6 +702,10 @@ bool
XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope,
HandleScript enclosingScript, MutableHandleFunction objp);
extern JSObject*
CloneFunctionAndScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
PollutedGlobalScopeOption polluted);
/*
* Report an error that call.thisv is not compatible with the specified class,
* assuming that the method (clasp->name).prototype.<name of callee function>

View File

@ -85,12 +85,7 @@ CloneFunctionObjectIfNotSingleton(JSContext* cx, HandleFunction fun, HandleObjec
gc::AllocKind kind = fun->isExtended()
? extendedFinalizeKind
: finalizeKind;
if (CanReuseScriptForClone(cx->compartment(), fun, parent))
return CloneFunctionReuseScript(cx, fun, parent, kind, newKind, proto);
RootedObject staticScope(cx, fun->getOrCreateScript(cx)->enclosingStaticScope());
return CloneFunctionAndScript(cx, fun, parent, staticScope, kind, proto);
return CloneFunctionObject(cx, fun, parent, kind, newKind, proto);
}
} /* namespace js */

View File

@ -1076,7 +1076,7 @@ NewObjectGCKind(const js::Class* clasp)
static inline JSObject*
NewObject(ExclusiveContext* cx, HandleObjectGroup group, gc::AllocKind kind,
NewObjectKind newKind, uint32_t initialShapeFlags = 0)
NewObjectKind newKind)
{
const Class* clasp = group->clasp();
@ -1091,8 +1091,7 @@ NewObject(ExclusiveContext* cx, HandleObjectGroup group, gc::AllocKind kind,
? GetGCKindSlots(gc::GetGCObjectKind(clasp), clasp)
: GetGCKindSlots(kind, clasp);
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, group->proto(), nfixed,
initialShapeFlags));
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, group->proto(), nfixed));
if (!shape)
return nullptr;
@ -1140,8 +1139,7 @@ NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto>
JSObject*
js::NewObjectWithGivenTaggedProto(ExclusiveContext* cxArg, const Class* clasp,
Handle<TaggedProto> proto,
gc::AllocKind allocKind, NewObjectKind newKind,
uint32_t initialShapeFlags)
gc::AllocKind allocKind, NewObjectKind newKind)
{
if (CanBeFinalizedInBackground(allocKind, clasp))
allocKind = GetBackgroundAllocKind(allocKind);
@ -1163,7 +1161,7 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext* cxArg, const Class* clasp,
if (!group)
return nullptr;
RootedObject obj(cxArg, NewObject(cxArg, group, allocKind, newKind, initialShapeFlags));
RootedObject obj(cxArg, NewObject(cxArg, group, allocKind, newKind));
if (!obj)
return nullptr;

View File

@ -216,35 +216,16 @@ class JSObject : public js::gc::Cell
return setFlags(cx, js::BaseShape::WATCHED, GENERATE_SHAPE);
}
// A "qualified" varobj is the object on which "qualified" variable
// declarations (i.e., those defined with "var") are kept.
//
// Conceptually, when a var binding is defined, it is defined on the
// innermost qualified varobj on the scope chain.
//
// Function scopes (CallObjects) are qualified varobjs, and there can be
// no other qualified varobj that is more inner for var bindings in that
// function. As such, all references to local var bindings in a function
// may be statically bound to the function scope. This is subject to
// further optimization. Unaliased bindings inside functions reside
// entirely on the frame, not in CallObjects.
//
// Global scopes are also qualified varobjs. It is possible to statically
// know, for a given script, that are no more inner qualified varobjs, so
// free variable references can be statically bound to the global.
//
// Finally, there are non-syntactic qualified varobjs used by embedders
// (e.g., Gecko and XPConnect), as they often wish to run scripts under a
// scope that captures var bindings.
inline bool isQualifiedVarObj() const;
/* See InterpreterFrame::varObj. */
inline bool isQualifiedVarObj();
bool setQualifiedVarObj(js::ExclusiveContext* cx) {
return setFlags(cx, js::BaseShape::QUALIFIED_VAROBJ);
}
// An "unqualified" varobj is the object on which "unqualified"
// assignments (i.e., bareword assignments for which the LHS does not
// exist on the scope chain) are kept.
inline bool isUnqualifiedVarObj() const;
inline bool isUnqualifiedVarObj();
bool setUnqualifiedVarObj(js::ExclusiveContext* cx) {
return setFlags(cx, js::BaseShape::UNQUALIFIED_VAROBJ);
}
/*
* Objects with an uncacheable proto can have their prototype mutated
@ -441,10 +422,10 @@ class JSObject : public js::gc::Cell
* slot of the object. For other scope objects, the chain goes directly to
* the global.
*
* In code which is not marked hasNonSyntacticScope, scope chains can
* In code which is not marked hasPollutedGlobalScope, scope chains can
* contain only syntactic scope objects (see IsSyntacticScope) with a global
* object at the root as the scope of the outermost non-function script. In
* hasNonSyntacticScope code, the scope of the outermost non-function
* hasPollutedGlobalScope code, the scope of the outermost non-function
* script might not be a global object, and can have a mix of other objects
* above it before the global object is reached.
*/

View File

@ -220,25 +220,19 @@ js::DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResul
/* * */
inline bool
JSObject::isQualifiedVarObj() const
JSObject::isQualifiedVarObj()
{
if (is<js::DebugScopeObject>())
return as<js::DebugScopeObject>().scope().isQualifiedVarObj();
bool rv = hasAllFlags(js::BaseShape::QUALIFIED_VAROBJ);
MOZ_ASSERT_IF(rv,
is<js::GlobalObject>() ||
is<js::CallObject>() ||
is<js::NonSyntacticVariablesObject>() ||
(is<js::DynamicWithObject>() && !as<js::DynamicWithObject>().isSyntactic()));
return rv;
return hasAllFlags(js::BaseShape::QUALIFIED_VAROBJ);
}
inline bool
JSObject::isUnqualifiedVarObj() const
JSObject::isUnqualifiedVarObj()
{
if (is<js::DebugScopeObject>())
return as<js::DebugScopeObject>().scope().isUnqualifiedVarObj();
return is<js::GlobalObject>() || is<js::NonSyntacticVariablesObject>();
return hasAllFlags(js::BaseShape::UNQUALIFIED_VAROBJ);
}
namespace js {
@ -609,38 +603,25 @@ typedef AutoVectorRooter<PropertyDescriptor> AutoPropertyDescriptorVector;
*/
JSObject*
NewObjectWithGivenTaggedProto(ExclusiveContext* cx, const Class* clasp, Handle<TaggedProto> proto,
gc::AllocKind allocKind, NewObjectKind newKind,
uint32_t initialShapeFlags = 0);
gc::AllocKind allocKind, NewObjectKind newKind);
inline JSObject*
NewObjectWithGivenTaggedProto(ExclusiveContext* cx, const Class* clasp, Handle<TaggedProto> proto,
NewObjectKind newKind = GenericObject,
uint32_t initialShapeFlags = 0)
NewObjectKind newKind = GenericObject)
{
gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
return NewObjectWithGivenTaggedProto(cx, clasp, proto, allocKind, newKind, initialShapeFlags);
return NewObjectWithGivenTaggedProto(cx, clasp, proto, allocKind, newKind);
}
template <typename T>
inline T*
NewObjectWithGivenTaggedProto(ExclusiveContext* cx, Handle<TaggedProto> proto,
NewObjectKind newKind = GenericObject,
uint32_t initialShapeFlags = 0)
NewObjectKind newKind = GenericObject)
{
JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, proto, newKind,
initialShapeFlags);
JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, proto, newKind);
return obj ? &obj->as<T>() : nullptr;
}
template <typename T>
inline T*
NewObjectWithNullTaggedProto(ExclusiveContext* cx, NewObjectKind newKind = GenericObject,
uint32_t initialShapeFlags = 0)
{
Rooted<TaggedProto> nullProto(cx, TaggedProto(nullptr));
return NewObjectWithGivenTaggedProto<T>(cx, nullProto, newKind, initialShapeFlags);
}
inline JSObject*
NewObjectWithGivenProto(ExclusiveContext* cx, const Class* clasp, HandleObject proto,
gc::AllocKind allocKind, NewObjectKind newKind)

View File

@ -576,10 +576,10 @@ enum XDRClassKind {
template<XDRMode mode>
bool
js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript enclosingScript,
js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
HandleFunction fun, MutableHandleScript scriptp)
{
/* NB: Keep this in sync with CopyScript. */
/* NB: Keep this in sync with CloneScript. */
enum ScriptBits {
NoScriptRval,
@ -600,7 +600,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
HasSingleton,
TreatAsRunOnce,
HasLazyScript,
HasNonSyntacticScope,
HasPollutedGlobalScope,
};
uint32_t length, lineno, column, nslots, staticLevel;
@ -613,7 +613,6 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
JSContext* cx = xdr->cx();
RootedScript script(cx);
RootedObject enclosingScope(cx, enclosingScopeArg);
natoms = nsrcnotes = 0;
nconsts = nobjects = nregexps = ntrynotes = nblockscopes = nyieldoffsets = 0;
@ -733,8 +732,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
scriptBits |= (1 << TreatAsRunOnce);
if (script->isRelazifiable())
scriptBits |= (1 << HasLazyScript);
if (script->hasNonSyntacticScope())
scriptBits |= (1 << HasNonSyntacticScope);
if (script->hasPollutedGlobalScope())
scriptBits |= (1 << HasPollutedGlobalScope);
}
if (!xdr->codeUint32(&prologueLength))
@ -802,26 +801,10 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
MOZ_ASSERT(enclosingScript->sourceObject()->is<ScriptSourceObject>());
sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>();
}
// If the outermost script has a non-syntactic scope, reflect that on
// the static scope chain.
if (scriptBits & (1 << HasNonSyntacticScope) && !enclosingScope) {
enclosingScope = StaticNonSyntacticScopeObjects::create(cx, nullptr);
if (!enclosingScope)
return false;
}
script = JSScript::Create(cx, enclosingScope, !!(scriptBits & (1 << SavedCallerFun)),
options, /* staticLevel = */ 0, sourceObject, 0, 0);
if (!script)
return false;
// Set the script in its function now so that inner scripts to be
// decoded may iterate the static scope chain.
if (fun) {
fun->initScript(script);
script->setFunction(fun);
}
}
/* JSScript::partiallyInit assumes script->bindings is fully initialized. */
@ -866,8 +849,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
script->hasSingletons_ = true;
if (scriptBits & (1 << TreatAsRunOnce))
script->treatAsRunOnce_ = true;
if (scriptBits & (1 << HasNonSyntacticScope))
script->hasNonSyntacticScope_ = true;
if (scriptBits & (1 << HasPollutedGlobalScope))
script->hasPollutedGlobalScope_ = true;
if (scriptBits & (1 << IsLegacyGenerator)) {
MOZ_ASSERT(!(scriptBits & (1 << IsStarGenerator)));
@ -999,12 +982,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
MOZ_ASSERT(enclosingStaticScopeIndex < i);
enclosingStaticScope = script->objects()->vector[enclosingStaticScopeIndex];
} else {
// This is not ternary because MSVC can't typecheck the
// ternary.
if (fun)
enclosingStaticScope = fun;
else
enclosingStaticScope = enclosingScope;
enclosingStaticScope = fun;
}
}
@ -1041,15 +1019,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
StaticScopeIter<NoGC> ssi(funEnclosingScope);
// Starting from a nested function, hitting a non-syntactic
// scope on the static scope chain means that its enclosing
// function has a non-syntactic scope. Nested functions
// themselves never have non-syntactic scope chains.
if (ssi.done() ||
ssi.type() == StaticScopeIter<NoGC>::NonSyntactic ||
ssi.type() == StaticScopeIter<NoGC>::Function)
{
MOZ_ASSERT_IF(ssi.done() || ssi.type() != StaticScopeIter<NoGC>::Function, !fun);
if (ssi.done() || ssi.type() == StaticScopeIter<NoGC>::Function) {
MOZ_ASSERT(ssi.done() == !fun);
funEnclosingScopeIndex = UINT32_MAX;
} else if (ssi.type() == StaticScopeIter<NoGC>::Block) {
funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block());
@ -1065,12 +1036,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
if (mode == XDR_DECODE) {
if (funEnclosingScopeIndex == UINT32_MAX) {
// This is not ternary because MSVC can't typecheck the
// ternary.
if (fun)
funEnclosingScope = fun;
else
funEnclosingScope = enclosingScope;
funEnclosingScope = fun;
} else {
MOZ_ASSERT(funEnclosingScopeIndex < i);
funEnclosingScope = script->objects()->vector[funEnclosingScopeIndex];
@ -1211,13 +1177,9 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript
return false;
}
if (mode == XDR_DECODE) {
if (mode == XDR_DECODE)
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript,
packedFields, begin, end, lineno, column));
if (!lazy)
return false;
fun->initLazyScript(lazy);
}
}
// Code free variables.
@ -2467,16 +2429,11 @@ JSScript::Create(ExclusiveContext* cx, HandleObject enclosingScope, bool savedCa
script->savedCallerFun_ = savedCallerFun;
script->initCompartment(cx);
script->hasPollutedGlobalScope_ = options.hasPollutedGlobalScope;
script->selfHosted_ = options.selfHostingMode;
script->noScriptRval_ = options.noScriptRval;
script->treatAsRunOnce_ = options.isRunOnce;
// Compute whether this script is under a non-syntactic scope. We don't
// need to walk the entire static scope chain if the script is nested in a
// function. In that case, we can propagate the cached value from the
// outer script.
script->hasNonSyntacticScope_ = HasNonSyntacticStaticScopeChain(enclosingScope);
script->version = options.version;
MOZ_ASSERT(script->getVersion() == options.version); // assert that no overflow occurred
@ -2694,6 +2651,7 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
script->funHasExtensibleScope_ = funbox ? funbox->hasExtensibleScope() : false;
script->funNeedsDeclEnvObject_ = funbox ? funbox->needsDeclEnvObject() : false;
script->needsHomeObject_ = funbox ? funbox->needsHomeObject() : false;
script->isDerivedClassConstructor_ = funbox ? funbox->isDerivedClassConstructor() : false;
script->hasSingletons_ = bce->hasSingletons;
if (funbox) {
@ -2711,13 +2669,10 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
RootedFunction fun(cx, nullptr);
if (funbox) {
// The function should have already been earlier to enable
// StaticScopeIter to walk the static scope chain of
// currently compiling scripts.
MOZ_ASSERT(script->functionNonDelazifying() == funbox->function());
MOZ_ASSERT(!bce->script->noScriptRval());
script->isGeneratorExp_ = funbox->inGenexpLambda;
script->setGeneratorKind(funbox->generatorKind());
script->setFunction(funbox->function());
if (bce->yieldOffsetList.length() != 0)
bce->yieldOffsetList.finish(script->yieldOffsets(), prologueLength);
}
@ -3050,48 +3005,15 @@ Rebase(JSScript* dst, JSScript* src, T* srcp)
return reinterpret_cast<T*>(dst->data + off);
}
static JSObject*
CloneInnerInterpretedFunction(JSContext* cx, HandleObject enclosingScope, HandleFunction srcFun)
{
/* NB: Keep this in sync with XDRInterpretedFunction. */
RootedObject cloneProto(cx);
if (srcFun->isStarGenerator()) {
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
if (!cloneProto)
return nullptr;
}
gc::AllocKind allocKind = srcFun->getAllocKind();
RootedFunction clone(cx, NewFunctionWithProto(cx, nullptr, 0,
JSFunction::INTERPRETED, nullptr, nullptr,
cloneProto, allocKind, TenuredObject));
if (!clone)
return nullptr;
JSScript::AutoDelazify srcScript(cx, srcFun);
if (!srcScript)
return nullptr;
JSScript* cloneScript = CloneScriptIntoFunction(cx, enclosingScope, clone, srcScript);
if (!cloneScript)
return nullptr;
clone->setArgCount(srcFun->nargs());
clone->setFlags(srcFun->flags());
clone->initAtom(srcFun->displayAtom());
if (!JSFunction::setTypeForScriptedFunction(cx, clone))
return nullptr;
return clone;
}
bool
js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScript src,
HandleScript dst)
JSScript*
js::CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun, HandleScript src,
PollutedGlobalScopeOption polluted /* = HasCleanGlobalScope */,
NewObjectKind newKind /* = GenericObject */)
{
if (src->treatAsRunOnce() && !src->functionNonDelazifying()) {
// Toplevel run-once scripts may not be cloned.
JS_ReportError(cx, "No cloning toplevel run-once scripts");
return false;
return nullptr;
}
/* NB: Keep this in sync with XDRScript. */
@ -3104,14 +3026,13 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
uint32_t nregexps = src->hasRegexps() ? src->regexps()->length : 0;
uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
uint32_t nblockscopes = src->hasBlockScopes() ? src->blockScopes()->length : 0;
uint32_t nyieldoffsets = src->hasYieldOffsets() ? src->yieldOffsets().length() : 0;
/* Script data */
size_t size = src->dataSize();
uint8_t* data = AllocScriptData(cx->zone(), size);
if (size && !data)
return false;
return nullptr;
/* Bindings */
@ -3119,7 +3040,7 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
InternalHandle<Bindings*> bindingsHandle =
InternalHandle<Bindings*>::fromMarkedLocation(bindings.address());
if (!Bindings::clone(cx, bindingsHandle, data, src))
return false;
return nullptr;
/* Objects */
@ -3136,7 +3057,7 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
if (NestedScopeObject* enclosingBlock = innerBlock->enclosingNestedScope())
enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)];
else
enclosingScope = scriptStaticScope;
enclosingScope = fun;
clone = CloneNestedScopeObject(cx, enclosingScope, innerBlock);
} else if (obj->is<JSFunction>()) {
@ -3145,36 +3066,32 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
if (cx->compartment() != innerFun->compartment()) {
MOZ_ASSERT(innerFun->isAsmJSNative());
JS_ReportError(cx, "AsmJS modules do not yet support cloning.");
return false;
return nullptr;
}
clone = innerFun;
} else {
if (innerFun->isInterpretedLazy()) {
AutoCompartment ac(cx, innerFun);
if (!innerFun->getOrCreateScript(cx))
return false;
return nullptr;
}
RootedObject staticScope(cx, innerFun->nonLazyScript()->enclosingStaticScope());
StaticScopeIter<CanGC> ssi(cx, staticScope);
RootedObject enclosingScope(cx);
if (ssi.done() || ssi.type() == StaticScopeIter<CanGC>::NonSyntactic) {
enclosingScope = scriptStaticScope;
} else if (ssi.type() == StaticScopeIter<CanGC>::Function) {
MOZ_ASSERT(scriptStaticScope->is<JSFunction>());
enclosingScope = scriptStaticScope;
} else if (ssi.type() == StaticScopeIter<CanGC>::Block) {
if (ssi.done() || ssi.type() == StaticScopeIter<CanGC>::Function)
enclosingScope = fun;
else if (ssi.type() == StaticScopeIter<CanGC>::Block)
enclosingScope = objects[FindScopeObjectIndex(src, ssi.block())];
} else {
else
enclosingScope = objects[FindScopeObjectIndex(src, ssi.staticWith())];
}
clone = CloneInnerInterpretedFunction(cx, enclosingScope, innerFun);
clone = CloneFunctionAndScript(cx, enclosingScope, innerFun, polluted);
}
} else {
clone = DeepCloneObjectLiteral(cx, obj, TenuredObject);
}
if (!clone || !objects.append(clone))
return false;
return nullptr;
}
}
@ -3186,11 +3103,50 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
for (unsigned i = 0; i < nregexps; i++) {
JSObject* clone = CloneScriptRegExpObject(cx, vector[i]->as<RegExpObject>());
if (!clone || !regexps.append(clone))
return false;
return nullptr;
}
}
/* Now that all fallible allocation is complete, do the copying. */
/*
* Wrap the script source object as needed. Self-hosted scripts may be
* in another runtime, so lazily create a new script source object to
* use for them.
*/
RootedObject sourceObject(cx);
if (cx->runtime()->isSelfHostingCompartment(src->compartment())) {
if (!cx->compartment()->selfHostingScriptSource) {
CompileOptions options(cx);
FillSelfHostingCompileOptions(options);
ScriptSourceObject* obj = frontend::CreateScriptSourceObject(cx, options);
if (!obj)
return nullptr;
cx->compartment()->selfHostingScriptSource.set(obj);
}
sourceObject = cx->compartment()->selfHostingScriptSource;
} else {
sourceObject = src->sourceObject();
if (!cx->compartment()->wrap(cx, &sourceObject))
return nullptr;
}
/* Now that all fallible allocation is complete, create the GC thing. */
CompileOptions options(cx);
options.setMutedErrors(src->mutedErrors())
.setHasPollutedScope(src->hasPollutedGlobalScope() ||
polluted == HasPollutedGlobalScope)
.setSelfHostingMode(src->selfHosted())
.setNoScriptRval(src->noScriptRval())
.setVersion(src->getVersion());
RootedScript dst(cx, JSScript::Create(cx, enclosingScope, src->savedCallerFun(),
options, src->staticLevel(),
sourceObject, src->sourceStart(), src->sourceEnd()));
if (!dst) {
js_free(data);
return nullptr;
}
dst->bindings = bindings;
@ -3249,112 +3205,64 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
if (nblockscopes != 0)
dst->blockScopes()->vector = Rebase<BlockScopeNote>(dst, src, src->blockScopes()->vector);
if (nyieldoffsets != 0)
dst->yieldOffsets().vector_ = Rebase<uint32_t>(dst, src, src->yieldOffsets().vector_);
/*
* Function delazification assumes that their script does not have a
* non-syntactic global scope. We ensure that as follows:
* polluted global scope. We ensure that as follows:
*
* 1) Initial parsing only creates lazy functions if
* !hasNonSyntacticScope.
* !hasPollutedGlobalScope.
* 2) Cloning a lazy function into a non-global scope will always require
* that its script be cloned. See comments in
* CloneFunctionObjectUseSameScript.
* 3) Cloning a script never sets a lazyScript on the clone, so the function
* cannot be relazified.
*
* If you decide that lazy functions should be supported with a
* non-syntactic global scope, make sure delazification can deal.
* If you decide that lazy functions should be supported with a polluted
* global scope, make sure delazification can deal.
*/
MOZ_ASSERT_IF(dst->hasNonSyntacticScope(), !dst->maybeLazyScript());
MOZ_ASSERT_IF(dst->hasNonSyntacticScope(), !dst->isRelazifiable());
MOZ_ASSERT_IF(dst->hasPollutedGlobalScope(), !dst->maybeLazyScript());
MOZ_ASSERT_IF(dst->hasPollutedGlobalScope(), !dst->isRelazifiable());
return dst;
}
bool
js::CloneFunctionScript(JSContext* cx, HandleFunction original, HandleFunction clone,
PollutedGlobalScopeOption polluted, NewObjectKind newKind)
{
RootedScript script(cx, clone->nonLazyScript());
MOZ_ASSERT(script);
MOZ_ASSERT(script->compartment() == original->compartment());
MOZ_ASSERT(cx->compartment() == clone->compartment(),
"Otherwise we could relazify clone below!");
// The only scripts with enclosing static scopes that may be cloned across
// compartments are non-strict, indirect eval scripts, as their dynamic
// scope chains terminate in the global scope immediately.
RootedObject scope(cx, script->enclosingStaticScope());
if (script->compartment() != cx->compartment() && scope) {
MOZ_ASSERT(!scope->as<StaticEvalObject>().isDirect() &&
!scope->as<StaticEvalObject>().isStrict());
scope = StaticEvalObject::create(cx, nullptr);
if (!scope)
return false;
}
clone->initScript(nullptr);
JSScript* cscript = CloneScript(cx, scope, clone, script, polluted, newKind);
if (!cscript)
return false;
clone->setScript(cscript);
cscript->setFunction(clone);
script = clone->nonLazyScript();
Debugger::onNewScript(cx, script);
return true;
}
static JSScript*
CreateEmptyScriptForClone(JSContext* cx, HandleObject enclosingScope, HandleScript src)
{
/*
* Wrap the script source object as needed. Self-hosted scripts may be
* in another runtime, so lazily create a new script source object to
* use for them.
*/
RootedObject sourceObject(cx);
if (cx->runtime()->isSelfHostingCompartment(src->compartment())) {
if (!cx->compartment()->selfHostingScriptSource) {
CompileOptions options(cx);
FillSelfHostingCompileOptions(options);
ScriptSourceObject* obj = frontend::CreateScriptSourceObject(cx, options);
if (!obj)
return nullptr;
cx->compartment()->selfHostingScriptSource.set(obj);
}
sourceObject = cx->compartment()->selfHostingScriptSource;
} else {
sourceObject = src->sourceObject();
if (!cx->compartment()->wrap(cx, &sourceObject))
return nullptr;
}
CompileOptions options(cx);
options.setMutedErrors(src->mutedErrors())
.setSelfHostingMode(src->selfHosted())
.setNoScriptRval(src->noScriptRval())
.setVersion(src->getVersion());
return JSScript::Create(cx, enclosingScope, src->savedCallerFun(),
options, src->staticLevel(),
sourceObject, src->sourceStart(), src->sourceEnd());
}
JSScript*
js::CloneGlobalScript(JSContext* cx, Handle<ScopeObject*> enclosingScope, HandleScript src)
{
// No enclosingScope means clean global.
MOZ_ASSERT(!enclosingScope || enclosingScope->is<StaticNonSyntacticScopeObjects>());
RootedScript dst(cx, CreateEmptyScriptForClone(cx, enclosingScope, src));
if (!dst)
return nullptr;
if (!detail::CopyScript(cx, enclosingScope, src, dst))
return nullptr;
return dst;
}
JSScript*
js::CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
HandleScript src)
{
MOZ_ASSERT(fun->isInterpreted());
// Allocate the destination script up front and set it as the script of
// |fun|, which is to be its container.
//
// This is so that when cloning nested functions, they can walk the static
// scope chain via fun and correctly compute the presence of a
// non-syntactic global.
RootedScript dst(cx, CreateEmptyScriptForClone(cx, enclosingScope, src));
if (!dst)
return nullptr;
dst->setFunction(fun);
if (fun->isInterpretedLazy())
fun->setUnlazifiedScript(dst);
else
fun->initScript(dst);
if (!detail::CopyScript(cx, fun, src, dst)) {
fun->setScript(nullptr);
return nullptr;
}
return dst;
}
DebugScript*
JSScript::debugScript()
{
@ -3930,6 +3838,7 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
p.hasDirectEval = false;
p.directlyInsideEval = false;
p.usesArgumentsApplyAndThis = false;
p.isDerivedClassConstructor = false;
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
MOZ_ASSERT_IF(res, res->version() == version);

View File

@ -55,15 +55,6 @@ namespace frontend {
class UpvarCookie;
}
namespace detail {
// Do not call this directly! It is exposed for the friend declarations in
// this file.
bool
CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScript src, HandleScript dst);
} // namespace detail
}
/*
@ -139,10 +130,6 @@ struct BlockScopeArray {
};
class YieldOffsetArray {
friend bool
detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScript src,
HandleScript dst);
uint32_t* vector_; // Array of bytecode offsets.
uint32_t length_; // Count of bytecode offsets.
@ -768,6 +755,16 @@ bool
XDRScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
HandleFunction fun, MutableHandleScript scriptp);
enum PollutedGlobalScopeOption {
HasPollutedGlobalScope,
HasCleanGlobalScope
};
JSScript*
CloneScript(JSContext* cx, HandleObject enclosingScope, HandleFunction fun, HandleScript script,
PollutedGlobalScopeOption polluted = HasCleanGlobalScope,
NewObjectKind newKind = GenericObject);
template<XDRMode mode>
bool
XDRLazyScript(XDRState<mode>* xdr, HandleObject enclosingScope, HandleScript enclosingScript,
@ -787,13 +784,13 @@ class JSScript : public js::gc::TenuredCell
template <js::XDRMode mode>
friend
bool
js::XDRScript(js::XDRState<mode>* xdr, js::HandleObject enclosingScope,
js::HandleScript enclosingScript,
js::XDRScript(js::XDRState<mode>* xdr, js::HandleObject enclosingScope, js::HandleScript enclosingScript,
js::HandleFunction fun, js::MutableHandleScript scriptp);
friend bool
js::detail::CopyScript(JSContext* cx, js::HandleObject scriptStaticScope, js::HandleScript src,
js::HandleScript dst);
friend JSScript*
js::CloneScript(JSContext* cx, js::HandleObject enclosingScope, js::HandleFunction fun,
js::HandleScript src, js::PollutedGlobalScopeOption polluted,
js::NewObjectKind newKind);
public:
//
@ -939,7 +936,7 @@ class JSScript : public js::gc::TenuredCell
// True if the script has a non-syntactic scope on its dynamic scope chain.
// That is, there are objects about which we know nothing between the
// outermost syntactic scope and the global.
bool hasNonSyntacticScope_:1;
bool hasPollutedGlobalScope_:1;
// see Parser::selfHostingMode.
bool selfHosted_:1;
@ -1028,6 +1025,8 @@ class JSScript : public js::gc::TenuredCell
bool needsHomeObject_:1;
bool isDerivedClassConstructor_:1;
// Add padding so JSScript is gc::Cell aligned. Make padding protected
// instead of private to suppress -Wunused-private-field compiler warnings.
protected:
@ -1179,8 +1178,8 @@ class JSScript : public js::gc::TenuredCell
bool explicitUseStrict() const { return explicitUseStrict_; }
bool hasNonSyntacticScope() const {
return hasNonSyntacticScope_;
bool hasPollutedGlobalScope() const {
return hasPollutedGlobalScope_;
}
bool selfHosted() const { return selfHosted_; }
@ -1300,6 +1299,9 @@ class JSScript : public js::gc::TenuredCell
return needsHomeObject_;
}
bool isDerivedClassConstructor() const {
return isDerivedClassConstructor_;
}
/*
* As an optimization, even when argsHasLocalBinding, the function prologue
@ -1943,11 +1945,13 @@ class LazyScript : public gc::TenuredCell
uint32_t version : 8;
uint32_t numFreeVariables : 24;
uint32_t numInnerFunctions : 22;
uint32_t numInnerFunctions : 21;
uint32_t generatorKindBits : 2;
// N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
// If you add another boolean here, make sure to initialze it in
// LazyScript::CreateRaw().
uint32_t strict : 1;
uint32_t bindingsAccessedDynamically : 1;
uint32_t hasDebuggerStatement : 1;
@ -1956,6 +1960,7 @@ class LazyScript : public gc::TenuredCell
uint32_t usesArgumentsApplyAndThis : 1;
uint32_t hasBeenCloned : 1;
uint32_t treatAsRunOnce : 1;
uint32_t isDerivedClassConstructor : 1;
};
union {
@ -2127,6 +2132,13 @@ class LazyScript : public gc::TenuredCell
p_.treatAsRunOnce = true;
}
bool isDerivedClassConstructor() const {
return p_.isDerivedClassConstructor;
}
void setIsDerivedClassConstructor() {
p_.isDerivedClassConstructor = true;
}
const char* filename() const {
return scriptSource()->filename();
}
@ -2281,12 +2293,9 @@ DescribeScriptedCallerForCompilation(JSContext* cx, MutableHandleScript maybeScr
uint32_t* pcOffset, bool* mutedErrors,
LineOption opt = NOT_CALLED_FROM_JSOP_EVAL);
JSScript*
CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFunction fun,
HandleScript src);
JSScript*
CloneGlobalScript(JSContext* cx, Handle<ScopeObject*> enclosingScope, HandleScript src);
bool
CloneFunctionScript(JSContext* cx, HandleFunction original, HandleFunction clone,
PollutedGlobalScopeOption polluted, NewObjectKind newKind);
} /* namespace js */

View File

@ -4318,36 +4318,6 @@ ReflectTrackedOptimizations(JSContext* cx, unsigned argc, Value* vp)
return true;
}
#ifdef DEBUG
static bool
DumpStaticScopeChain(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject callee(cx, &args.callee());
if (args.length() != 1) {
ReportUsageError(cx, callee, "Wrong number of arguments");
return false;
}
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
ReportUsageError(cx, callee, "Argument must be an interpreted function");
return false;
}
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
if (!fun->isInterpreted()) {
ReportUsageError(cx, callee, "Argument must be an interpreted function");
return false;
}
js::DumpStaticScopeChain(fun->getOrCreateScript(cx));
args.rval().setUndefined();
return true;
}
#endif
namespace js {
namespace shell {
@ -4996,12 +4966,6 @@ static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = {
" any. If |fun| is not a scripted function or has not been compiled by\n"
" Ion, null is returned."),
#ifdef DEBUG
JS_FN_HELP("dumpStaticScopeChain", DumpStaticScopeChain, 1, 0,
"dumpStaticScopeChain(fun)",
" Prints the static scope chain of an interpreted function fun."),
#endif
JS_FS_HELP_END
};

View File

@ -0,0 +1,25 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
assertEq(new Function(
"eval('var foo = 915805');" +
"return foo;"
)(),
915805);
assertEq(new Function(
"eval('function foo() {" +
"return 915805;" +
"}');" +
"return foo;"
)()(),
915805);
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

View File

@ -0,0 +1,37 @@
// |reftest| skip-if(!xulRuntime.shell)
var test = `
class base {
constructor() {
eval('');
(()=>0)();
}
}
class derived extends base {
constructor() {
eval('');
}
}
// Make sure eval and arrows are still valid in non-derived constructors.
new base();
// Eval throws in derived class constructors, in both class expressions and
// statements.
assertThrowsInstanceOf((() => new derived()), InternalError);
assertThrowsInstanceOf((() => new class extends base { constructor() { eval('') } }()), InternalError);
var g = newGlobal();
var dbg = Debugger(g);
dbg.onDebuggerStatement = function(frame) { assertThrowsInstanceOf(()=>frame.eval(''), InternalError); };
g.eval("new class foo extends null { constructor() { debugger; } }()");
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -118,6 +118,9 @@ function testClasses() {
// Currently, we do not allow default constructors
assertClassError("class NAME { }", TypeError);
// For now, disallow arrow functions in derived class constructors
assertClassError("class NAME extends null { constructor() { (() => 0); }", InternalError);
// It is an error to have two methods named constructor, but not other
// names, regardless if one is an accessor or a generator or static.
assertClassError("class NAME { constructor() { } constructor(a) { } }", SyntaxError);

View File

@ -9,6 +9,7 @@ from __future__ import print_function
import os, sys, textwrap
from os.path import abspath, dirname, isfile, realpath
from contextlib import contextmanager
from copy import copy
from subprocess import list2cmdline, call
@ -22,15 +23,6 @@ if sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
else:
from lib.tasks_win import run_all_tests
def run_tests(options, tests, results):
"""Run the given tests, sending raw results to the given results
accumulator."""
try:
completed = run_all_tests(tests, results, options)
except KeyboardInterrupt:
completed = False
results.finish(completed)
def get_cpu_count():
"""
@ -62,6 +54,17 @@ def get_cpu_count():
return 1
@contextmanager
def changedir(dirname):
pwd = os.getcwd()
os.chdir(dirname)
try:
yield
finally:
os.chdir(pwd)
def parse_args():
"""
Parse command line arguments.
@ -191,14 +194,14 @@ def parse_args():
op.error("--valgrind, --debug, and --rr are mutually exclusive.")
# Fill the debugger field, as needed.
prefix = options.debugger.split() if options.debug else []
debugger_prefix = options.debugger.split() if options.debug else []
if options.valgrind:
prefix = ['valgrind'] + options.valgrind_args.split()
debugger_prefix = ['valgrind'] + options.valgrind_args.split()
if os.uname()[0] == 'Darwin':
prefix.append('--dsymutil=yes')
debugger_prefix.append('--dsymutil=yes')
options.show_output = True
if options.rr:
prefix = ['rr', 'record']
debugger_prefix = ['rr', 'record']
js_cmd_args = options.shell_args.split()
if options.jorendb:
@ -209,7 +212,8 @@ def parse_args():
abspath(dirname(abspath(__file__))),
'..', '..', 'examples', 'jorendb.js'))
js_cmd_args.extend(['-d', '-f', debugger_path, '--'])
TestCase.set_js_cmd_prefix(options.js_shell, js_cmd_args, prefix)
prefix = TestCase.build_js_cmd_prefix(options.js_shell, js_cmd_args,
debugger_prefix)
# If files with lists of tests to run were specified, add them to the
# requested tests set.
@ -248,7 +252,8 @@ def parse_args():
not ProgressBar.conservative_isatty() or
options.hide_progress)
return (options, requested_paths, excluded_paths)
return (options, prefix, requested_paths, excluded_paths)
def load_tests(options, requested_paths, excluded_paths):
"""
@ -324,8 +329,9 @@ def load_tests(options, requested_paths, excluded_paths):
return skip_list, test_list
def main():
options, requested_paths, excluded_paths = parse_args()
options, prefix, requested_paths, excluded_paths = parse_args()
if options.js_shell is not None and not isfile(options.js_shell):
print('Could not find shell at given path.')
return 1
@ -348,31 +354,26 @@ def main():
cmd = test_list[0].get_command(TestCase.js_cmd_prefix)
if options.show_cmd:
print(list2cmdline(cmd))
if test_dir not in ('', '.'):
os.chdir(test_dir)
call(cmd)
with changedir(test_dir):
call(cmd)
return 0
curdir = os.getcwd()
if test_dir not in ('', '.'):
os.chdir(test_dir)
with changedir(test_dir):
# Force Pacific time zone to avoid failures in Date tests.
os.environ['TZ'] = 'PST8PDT'
# Force date strings to English.
os.environ['LC_TIME'] = 'en_US.UTF-8'
# Force Pacific time zone to avoid failures in Date tests.
os.environ['TZ'] = 'PST8PDT'
# Force date strings to English.
os.environ['LC_TIME'] = 'en_US.UTF-8'
results = None
try:
results = ResultsSink(options, len(skip_list) + len(test_list))
for t in skip_list:
results.push(NullTestOutput(t))
run_tests(options, test_list, results)
finally:
os.chdir(curdir)
try:
for t in skip_list:
results.push(NullTestOutput(t))
ok = run_all_tests(test_list, prefix, results, options)
except KeyboardInterrupt:
ok = False
if results is None or not results.all_passed():
return 1
results.finish(ok)
return 0 if results.all_passed() else 1
return 0

View File

@ -7,9 +7,9 @@ from datetime import datetime, timedelta
from results import TestOutput
class Task(object):
def __init__(self, test, pid, stdout, stderr):
def __init__(self, test, prefix, pid, stdout, stderr):
self.test = test
self.cmd = test.get_command(test.js_cmd_prefix)
self.cmd = test.get_command(prefix)
self.pid = pid
self.stdout = stdout
self.stderr = stderr
@ -17,7 +17,7 @@ class Task(object):
self.out = []
self.err = []
def spawn_test(test, passthrough=False):
def spawn_test(test, prefix, passthrough=False):
"""Spawn one child, return a task struct."""
if not passthrough:
(rout, wout) = os.pipe()
@ -29,7 +29,7 @@ def spawn_test(test, passthrough=False):
if rv:
os.close(wout)
os.close(werr)
return Task(test, rv, rout, rerr)
return Task(test, prefix, rv, rout, rerr)
# Child.
os.close(rout)
@ -38,7 +38,7 @@ def spawn_test(test, passthrough=False):
os.dup2(wout, 1)
os.dup2(werr, 2)
cmd = test.get_command(test.js_cmd_prefix)
cmd = test.get_command(prefix)
os.execvp(cmd[0], cmd)
def total_seconds(td):
@ -180,7 +180,7 @@ def kill_undead(tasks, results, timeout):
if timed_out(task, timeout):
os.kill(task.pid, 9)
def run_all_tests(tests, results, options):
def run_all_tests(tests, prefix, results, options):
# Copy and reverse for fast pop off end.
tests = tests[:]
tests.reverse()
@ -190,7 +190,7 @@ def run_all_tests(tests, results, options):
while len(tests) or len(tasks):
while len(tests) and len(tasks) < options.worker_count:
tasks.append(spawn_test(tests.pop(), options.passthrough))
tasks.append(spawn_test(tests.pop(), prefix, options.passthrough))
timeout = get_max_wait(tasks, results, options.timeout)
read_input(tasks, timeout)

View File

@ -12,16 +12,16 @@ class EndMarker:
pass
def _do_work(qTasks, qResults, timeout):
def _do_work(qTasks, qResults, prefix, timeout):
while True:
test = qTasks.get(block=True, timeout=sys.maxint)
if test is EndMarker:
qResults.put(EndMarker)
return
qResults.put(test.run(test.js_cmd_prefix, timeout))
qResults.put(test.run(prefix, timeout))
def run_all_tests_gen(tests, results, options):
def run_all_tests_gen(tests, prefix, results, options):
"""
Uses scatter-gather to a thread-pool to manage children.
"""
@ -29,7 +29,8 @@ def run_all_tests_gen(tests, results, options):
workers = []
for _ in range(options.worker_count):
worker = Thread(target=_do_work, args=(qTasks, qResults, options.timeout))
worker = Thread(target=_do_work, args=(qTasks, qResults, prefix,
options.timeout))
worker.setDaemon(True)
worker.start()
workers.append(worker)
@ -60,8 +61,8 @@ def run_all_tests_gen(tests, results, options):
assert qResults.empty(), "Result queue not drained"
def run_all_tests(tests, results, options):
for result in run_all_tests_gen(tests, results, options):
def run_all_tests(tests, prefix, results, options):
for result in run_all_tests_gen(tests, prefix, results, options):
results.push(result)
return True

View File

@ -118,21 +118,19 @@ class Test(object):
return Test.prefix_command(head) \
+ ['-f', os.path.join(path, 'shell.js')]
def get_command(self, js_cmd_prefix):
def get_command(self, prefix):
dirname, filename = os.path.split(self.path)
cmd = js_cmd_prefix + self.jitflags + self.options \
cmd = prefix + self.jitflags + self.options \
+ Test.prefix_command(dirname) + ['-f', self.path]
return cmd
def run(self, js_cmd_prefix, timeout=30.0):
cmd = self.get_command(js_cmd_prefix)
def run(self, prefix, timeout=30.0):
cmd = self.get_command(prefix)
out, err, rc, dt, timed_out = run_cmd(cmd, timeout)
return TestOutput(self, cmd, out, err, rc, dt, timed_out)
class TestCase(Test):
"""A test case consisting of a test and an expected result."""
js_cmd_prefix = None
def __init__(self, path):
Test.__init__(self, path)
self.enable = True # bool: True => run test, False => don't run
@ -163,15 +161,15 @@ class TestCase(Test):
ans += ', debugMode'
return ans
@classmethod
def set_js_cmd_prefix(self, js_path, js_args, debugger_prefix):
@staticmethod
def build_js_cmd_prefix(js_path, js_args, debugger_prefix):
parts = []
if debugger_prefix:
parts += debugger_prefix
parts.append(js_path)
if js_args:
parts += js_args
self.js_cmd_prefix = parts
return parts
def __cmp__(self, other):
if self.path == other.path:

View File

@ -6261,14 +6261,12 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, HandleValue thisv, AbstractFrameP
* boundaries, and we are putting a DebugScopeProxy or non-syntactic With on
* the scope chain.
*/
Rooted<ScopeObject*> enclosingStaticScope(cx);
if (!env->is<GlobalObject>())
enclosingStaticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr);
Rooted<StaticEvalObject*> staticScope(cx, StaticEvalObject::create(cx, enclosingStaticScope));
Rooted<StaticEvalObject*> staticScope(cx, StaticEvalObject::create(cx, nullptr));
if (!staticScope)
return false;
CompileOptions options(cx);
options.setIsRunOnce(true)
options.setHasPollutedScope(true)
.setIsRunOnce(true)
.setForEval(true)
.setNoScriptRval(false)
.setFileAndLine(filename, lineno)
@ -6277,8 +6275,8 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, HandleValue thisv, AbstractFrameP
.maybeMakeStrictMode(frame ? frame.script()->strict() : false);
RootedScript callerScript(cx, frame ? frame.script() : nullptr);
SourceBufferHolder srcBuf(chars.start().get(), chars.length(), SourceBufferHolder::NoOwnership);
RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), env, staticScope,
callerScript, options, srcBuf,
RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), env, callerScript,
staticScope, options, srcBuf,
/* source = */ nullptr,
/* staticLevel = */ frame ? 1 : 0));
if (!script)
@ -6304,6 +6302,13 @@ DebuggerGenericEval(JSContext* cx, const char* fullMethodName, const Value& code
MOZ_ASSERT_IF(iter, !scope);
MOZ_ASSERT_IF(!iter, scope && scope->is<GlobalObject>());
if (iter && iter->script()->isDerivedClassConstructor()) {
MOZ_ASSERT(iter->isFunctionFrame() && iter->calleeTemplate()->isClassConstructor());
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DISABLED_DERIVED_CLASS,
"debugger eval");
return false;
}
/* Check the first argument, the eval code string. */
if (!code.isString()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
@ -6419,8 +6424,14 @@ DebuggerGenericEval(JSContext* cx, const char* fullMethodName, const Value& code
return false;
RootedObject dynamicScope(cx);
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, env, &dynamicScope))
// We ignore the static scope here. See comments about static
// scopes in EvaluateInEnv.
RootedObject unusedStaticScope(cx);
if (!CreateScopeObjectsForScopeChain(cx, scopeChain, env, &dynamicScope,
&unusedStaticScope))
{
return false;
}
env = dynamicScope;
}

View File

@ -247,7 +247,6 @@ GlobalObject::createInternal(JSContext* cx, const Class* clasp)
return nullptr;
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
MOZ_ASSERT(global->isUnqualifiedVarObj());
// Initialize the private slot to null if present, as GC can call class
// hooks before the caller gets to set this to a non-garbage value.
@ -258,6 +257,8 @@ GlobalObject::createInternal(JSContext* cx, const Class* clasp)
if (!global->setQualifiedVarObj(cx))
return nullptr;
if (!global->setUnqualifiedVarObj(cx))
return nullptr;
if (!global->setDelegate(cx))
return nullptr;

View File

@ -304,9 +304,9 @@ SetNameOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleObject s
*pc == JSOP_STRICTSETNAME ||
*pc == JSOP_SETGNAME ||
*pc == JSOP_STRICTSETGNAME);
MOZ_ASSERT_IF(*pc == JSOP_SETGNAME && !script->hasNonSyntacticScope(),
MOZ_ASSERT_IF(*pc == JSOP_SETGNAME && !script->hasPollutedGlobalScope(),
scope == cx->global());
MOZ_ASSERT_IF(*pc == JSOP_STRICTSETGNAME && !script->hasNonSyntacticScope(),
MOZ_ASSERT_IF(*pc == JSOP_STRICTSETGNAME && !script->hasPollutedGlobalScope(),
scope == cx->global());
bool strict = *pc == JSOP_STRICTSETNAME || *pc == JSOP_STRICTSETGNAME;

View File

@ -274,7 +274,7 @@ GetNameOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHan
* the actual behavior even if the id could be found on the scope chain
* before the global object.
*/
if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasNonSyntacticScope())
if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasPollutedGlobalScope())
obj = &obj->global();
Shape* shape = nullptr;
@ -868,7 +868,7 @@ js::ExecuteKernel(JSContext* cx, HandleScript script, JSObject& scopeChainArg, c
while (IsSyntacticScope(terminatingScope))
terminatingScope = terminatingScope->enclosingScope();
MOZ_ASSERT(terminatingScope->is<GlobalObject>() ||
script->hasNonSyntacticScope());
script->hasPollutedGlobalScope());
#endif
if (script->treatAsRunOnce()) {
@ -904,8 +904,8 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& scopeChainArg, Value*
RootedObject scopeChain(cx, &scopeChainArg);
MOZ_ASSERT(scopeChain == GetInnerObject(scopeChain));
MOZ_RELEASE_ASSERT(scopeChain->is<GlobalObject>() || script->hasNonSyntacticScope(),
"Only scripts with non-syntactic scopes can be executed with "
MOZ_RELEASE_ASSERT(scopeChain->is<GlobalObject>() || script->hasPollutedGlobalScope(),
"Only scripts with polluted scopes can be executed with "
"interesting scopechains");
/* Ensure the scope chain is all same-compartment and terminates in a global. */
@ -917,6 +917,12 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& scopeChainArg, Value*
} while ((s = s->enclosingScope()));
#endif
/* The VAROBJFIX option makes varObj == globalObj in global code. */
if (!cx->runtime()->options().varObjFix()) {
if (!scopeChain->setQualifiedVarObj(cx))
return false;
}
/* Use the scope chain as 'this', modulo outerization. */
JSObject* thisObj = GetThisObject(cx, scopeChain);
if (!thisObj)
@ -1176,7 +1182,6 @@ PopScope(JSContext* cx, ScopeIter& si)
break;
case ScopeIter::Call:
case ScopeIter::Eval:
case ScopeIter::NonSyntactic:
break;
}
}
@ -2315,7 +2320,7 @@ CASE(JSOP_BINDGNAME)
CASE(JSOP_BINDNAME)
{
JSOp op = JSOp(*REGS.pc);
if (op == JSOP_BINDNAME || script->hasNonSyntacticScope()) {
if (op == JSOP_BINDNAME || script->hasPollutedGlobalScope()) {
ReservedRooted<JSObject*> scopeChain(&rootObject0, REGS.fp()->scopeChain());
ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
@ -3057,7 +3062,7 @@ CASE(JSOP_IMPLICITTHIS)
CASE(JSOP_GIMPLICITTHIS)
{
JSOp op = JSOp(*REGS.pc);
if (op == JSOP_IMPLICITTHIS || script->hasNonSyntacticScope()) {
if (op == JSOP_IMPLICITTHIS || script->hasPollutedGlobalScope()) {
ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
ReservedRooted<JSObject*> scopeObj(&rootObject0, REGS.fp()->scopeChain());
ReservedRooted<JSObject*> scope(&rootObject1);
@ -3936,7 +3941,7 @@ CASE(JSOP_SUPERBASE)
{
ScopeIter si(cx, REGS.fp()->scopeChain(), REGS.fp()->script()->innermostStaticScope(REGS.pc));
for (; !si.done(); ++si) {
if (si.hasSyntacticScopeObject() && si.type() == ScopeIter::Call) {
if (si.hasScopeObject() && si.type() == ScopeIter::Call) {
JSFunction& callee = si.scope().as<CallObject>().callee();
// Arrow functions don't have the information we're looking for,

View File

@ -1570,9 +1570,9 @@
macro(JSOP_RETRVAL, 153,"retrval", NULL, 1, 0, 0, JOF_BYTE) \
\
/*
* Looks up name on global scope and pushes its value onto the stack,
* unless the script has a non-syntactic global scope, in which case it
* acts just like JSOP_NAME.
* Looks up name on global scope and pushes its value onto the stack, unless
* the script has a polluted global, in which case it acts just like
* JSOP_NAME.
*
* Free variable references that must either be found on the global or a
* ReferenceError.
@ -1586,7 +1586,7 @@
* Pops the top two values on the stack as 'val' and 'scope', sets property
* of 'scope' as 'val' and pushes 'val' back on the stack.
*
* 'scope' should be the global scope unless the script has a non-syntactic
* 'scope' should be the global scope unless the script has a polluted
* global scope, in which case acts like JSOP_SETNAME.
* Category: Variables and Scopes
* Type: Free Variables
@ -1600,7 +1600,7 @@
* of 'scope' as 'val' and pushes 'val' back on the stack. Throws a
* TypeError if the set fails, per strict mode semantics.
*
* 'scope' should be the global scope unless the script has a non-syntactic
* 'scope' should be the global scope unless the script has a polluted
* global scope, in which case acts like JSOP_STRICTSETNAME.
* Category: Variables and Scopes
* Type: Free Variables
@ -1871,7 +1871,7 @@
macro(JSOP_UNUSED213, 213, "unused213", NULL, 1, 0, 0, JOF_BYTE) \
/*
* Pushes the global scope onto the stack if the script doesn't have a
* non-syntactic global scope. Otherwise will act like JSOP_BINDNAME.
* polluted global scope. Otherwise will act like JSOP_BINDNAME.
*
* 'nameIndex' is only used when acting like JSOP_BINDNAME.
* Category: Variables and Scopes

View File

@ -84,8 +84,6 @@ StaticScopeIter<allowGC>::operator++(int)
obj = obj->template as<NestedScopeObject>().enclosingScopeForStaticScopeIter();
} else if (obj->template is<StaticEvalObject>()) {
obj = obj->template as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
} else if (obj->template is<StaticNonSyntacticScopeObjects>()) {
obj = obj->template as<StaticNonSyntacticScopeObjects>().enclosingScopeForStaticScopeIter();
} else if (onNamedLambda || !obj->template as<JSFunction>().isNamedLambda()) {
onNamedLambda = false;
obj = obj->template as<JSFunction>().nonLazyScript()->enclosingStaticScope();
@ -94,32 +92,27 @@ StaticScopeIter<allowGC>::operator++(int)
}
MOZ_ASSERT_IF(obj, obj->template is<NestedScopeObject>() ||
obj->template is<StaticEvalObject>() ||
obj->template is<StaticNonSyntacticScopeObjects>() ||
obj->template is<JSFunction>());
MOZ_ASSERT_IF(onNamedLambda, obj->template is<JSFunction>());
}
template <AllowGC allowGC>
inline bool
StaticScopeIter<allowGC>::hasSyntacticDynamicScopeObject() const
StaticScopeIter<allowGC>::hasDynamicScopeObject() const
{
if (obj->template is<JSFunction>())
return obj->template as<JSFunction>().isHeavyweight();
if (obj->template is<StaticBlockObject>())
return obj->template as<StaticBlockObject>().needsClone();
if (obj->template is<StaticWithObject>())
return true;
if (obj->template is<StaticEvalObject>())
return obj->template as<StaticEvalObject>().isStrict();
MOZ_ASSERT(obj->template is<StaticNonSyntacticScopeObjects>());
return false;
return obj->template is<StaticBlockObject>()
? obj->template as<StaticBlockObject>().needsClone()
: (obj->template is<StaticEvalObject>()
? obj->template as<StaticEvalObject>().isStrict()
: (obj->template is<StaticWithObject>() ||
obj->template as<JSFunction>().isHeavyweight()));
}
template <AllowGC allowGC>
inline Shape*
StaticScopeIter<allowGC>::scopeShape() const
{
MOZ_ASSERT(hasSyntacticDynamicScopeObject());
MOZ_ASSERT(hasDynamicScopeObject());
MOZ_ASSERT(type() != NamedLambda && type() != Eval);
if (type() == Block)
return block().lastProperty();
@ -138,8 +131,6 @@ StaticScopeIter<allowGC>::type() const
? With
: (obj->template is<StaticEvalObject>()
? Eval
: (obj->template is<StaticNonSyntacticScopeObjects>())
? NonSyntactic
: Function));
}
@ -167,14 +158,6 @@ StaticScopeIter<allowGC>::eval() const
return obj->template as<StaticEvalObject>();
}
template <AllowGC allowGC>
inline StaticNonSyntacticScopeObjects&
StaticScopeIter<allowGC>::nonSyntactic() const
{
MOZ_ASSERT(type() == NonSyntactic);
return obj->template as<StaticNonSyntacticScopeObjects>();
}
template <AllowGC allowGC>
inline JSScript*
StaticScopeIter<allowGC>::funScript() const

View File

@ -43,7 +43,7 @@ js::ScopeCoordinateToStaticScopeShape(JSScript* script, jsbytecode* pc)
uint32_t hops = ScopeCoordinate(pc).hops();
while (true) {
MOZ_ASSERT(!ssi.done());
if (ssi.hasSyntacticDynamicScopeObject()) {
if (ssi.hasDynamicScopeObject()) {
if (!hops)
break;
hops--;
@ -107,7 +107,7 @@ js::ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc)
StaticScopeIter<NoGC> ssi(script->innermostStaticScopeInScript(pc));
uint32_t hops = ScopeCoordinate(pc).hops();
while (true) {
if (ssi.hasSyntacticDynamicScopeObject()) {
if (ssi.hasDynamicScopeObject()) {
if (!hops)
break;
hops--;
@ -212,7 +212,7 @@ CallObject::create(JSContext* cx, HandleScript script, HandleObject enclosing, H
if (!callobj)
return nullptr;
callobj->setEnclosingScope(enclosing);
callobj->as<ScopeObject>().setEnclosingScope(enclosing);
callobj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee));
if (script->treatAsRunOnce()) {
@ -323,10 +323,22 @@ const Class DeclEnvObject::class_ = {
* scope and callee) or used as a template for jit compilation.
*/
DeclEnvObject*
DeclEnvObject::createTemplateObject(JSContext* cx, HandleFunction fun, NewObjectKind newKind)
DeclEnvObject::createTemplateObject(JSContext* cx, HandleFunction fun, gc::InitialHeap heap)
{
Rooted<DeclEnvObject*> obj(cx);
obj = NewObjectWithNullTaggedProto<DeclEnvObject>(cx, newKind, BaseShape::DELEGATE);
MOZ_ASSERT(IsNurseryAllocable(FINALIZE_KIND));
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
if (!group)
return nullptr;
RootedShape emptyDeclEnvShape(cx);
emptyDeclEnvShape = EmptyShape::getInitialShape(cx, &class_, TaggedProto(nullptr),
FINALIZE_KIND, BaseShape::DELEGATE);
if (!emptyDeclEnvShape)
return nullptr;
RootedNativeObject obj(cx, MaybeNativeObject(JSObject::create(cx, FINALIZE_KIND, heap,
emptyDeclEnvShape, group)));
if (!obj)
return nullptr;
@ -344,13 +356,13 @@ DeclEnvObject::createTemplateObject(JSContext* cx, HandleFunction fun, NewObject
return nullptr;
MOZ_ASSERT(!obj->hasDynamicSlots());
return obj;
return &obj->as<DeclEnvObject>();
}
DeclEnvObject*
DeclEnvObject::create(JSContext* cx, HandleObject enclosing, HandleFunction callee)
{
Rooted<DeclEnvObject*> obj(cx, createTemplateObject(cx, callee, GenericObject));
Rooted<DeclEnvObject*> obj(cx, createTemplateObject(cx, callee, gc::DefaultHeap));
if (!obj)
return nullptr;
@ -388,7 +400,20 @@ js::XDRStaticWithObject(XDRState<XDR_DECODE>*, HandleObject, MutableHandle<Stati
StaticWithObject*
StaticWithObject::create(ExclusiveContext* cx)
{
return NewObjectWithNullTaggedProto<StaticWithObject>(cx, TenuredObject, BaseShape::DELEGATE);
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
if (!group)
return nullptr;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(nullptr),
FINALIZE_KIND));
if (!shape)
return nullptr;
RootedObject obj(cx, JSObject::create(cx, FINALIZE_KIND, gc::TenuredHeap, shape, group));
if (!obj)
return nullptr;
return &obj->as<StaticWithObject>();
}
static JSObject*
@ -408,11 +433,18 @@ DynamicWithObject::create(JSContext* cx, HandleObject object, HandleObject enclo
HandleObject staticWith, WithKind kind)
{
MOZ_ASSERT(staticWith->is<StaticWithObject>());
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_,
TaggedProto(staticWith.get())));
if (!group)
return nullptr;
Rooted<TaggedProto> proto(cx, TaggedProto(staticWith));
Rooted<DynamicWithObject*> obj(cx);
obj = NewObjectWithGivenTaggedProto<DynamicWithObject>(cx, proto, GenericObject,
BaseShape::DELEGATE);
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(staticWith),
FINALIZE_KIND));
if (!shape)
return nullptr;
RootedNativeObject obj(cx, MaybeNativeObject(JSObject::create(cx, FINALIZE_KIND,
gc::DefaultHeap, shape, group)));
if (!obj)
return nullptr;
@ -420,12 +452,12 @@ DynamicWithObject::create(JSContext* cx, HandleObject object, HandleObject enclo
if (!thisp)
return nullptr;
obj->setEnclosingScope(enclosing);
obj->as<ScopeObject>().setEnclosingScope(enclosing);
obj->setFixedSlot(OBJECT_SLOT, ObjectValue(*object));
obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp));
obj->setFixedSlot(KIND_SLOT, Int32Value(kind));
return obj;
return &obj->as<DynamicWithObject>();
}
static bool
@ -535,14 +567,23 @@ const Class DynamicWithObject::class_ = {
/* static */ StaticEvalObject*
StaticEvalObject::create(JSContext* cx, HandleObject enclosing)
{
StaticEvalObject* obj =
NewObjectWithNullTaggedProto<StaticEvalObject>(cx, TenuredObject, BaseShape::DELEGATE);
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
if (!group)
return nullptr;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(nullptr),
FINALIZE_KIND, BaseShape::DELEGATE));
if (!shape)
return nullptr;
RootedNativeObject obj(cx, MaybeNativeObject(JSObject::create(cx, FINALIZE_KIND,
gc::TenuredHeap, shape, group)));
if (!obj)
return nullptr;
obj->setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(enclosing));
obj->setReservedSlot(STRICT_SLOT, BooleanValue(false));
return obj;
return &obj->as<StaticEvalObject>();
}
const Class StaticEvalObject::class_ = {
@ -551,48 +592,6 @@ const Class StaticEvalObject::class_ = {
JSCLASS_IS_ANONYMOUS
};
/* static */ StaticNonSyntacticScopeObjects*
StaticNonSyntacticScopeObjects::create(JSContext*cx, HandleObject enclosing)
{
StaticNonSyntacticScopeObjects* obj =
NewObjectWithNullTaggedProto<StaticNonSyntacticScopeObjects>(cx, TenuredObject,
BaseShape::DELEGATE);
if (!obj)
return nullptr;
obj->setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(enclosing));
return obj;
}
const Class StaticNonSyntacticScopeObjects::class_ = {
"StaticNonSyntacticScopeObjects",
JSCLASS_HAS_RESERVED_SLOTS(StaticNonSyntacticScopeObjects::RESERVED_SLOTS) |
JSCLASS_IS_ANONYMOUS
};
/* static */ NonSyntacticVariablesObject*
NonSyntacticVariablesObject::create(JSContext* cx, Handle<GlobalObject*> global)
{
Rooted<NonSyntacticVariablesObject*> obj(cx,
NewObjectWithNullTaggedProto<NonSyntacticVariablesObject>(cx, TenuredObject,
BaseShape::DELEGATE));
if (!obj)
return nullptr;
MOZ_ASSERT(obj->isUnqualifiedVarObj());
if (!obj->setQualifiedVarObj(cx))
return nullptr;
obj->setEnclosingScope(global);
return obj;
}
const Class NonSyntacticVariablesObject::class_ = {
"NonSyntacticVariablesObject",
JSCLASS_HAS_RESERVED_SLOTS(NonSyntacticVariablesObject::RESERVED_SLOTS) |
JSCLASS_IS_ANONYMOUS
};
/*****************************************************************************/
/* static */ ClonedBlockObject*
@ -607,10 +606,7 @@ ClonedBlockObject::create(JSContext* cx, Handle<StaticBlockObject*> block, Handl
RootedShape shape(cx, block->lastProperty());
gc::AllocKind allocKind = gc::GetGCObjectKind(&BlockObject::class_);
if (CanBeFinalizedInBackground(allocKind, &BlockObject::class_))
allocKind = GetBackgroundAllocKind(allocKind);
RootedNativeObject obj(cx, MaybeNativeObject(JSObject::create(cx, allocKind,
RootedNativeObject obj(cx, MaybeNativeObject(JSObject::create(cx, FINALIZE_KIND,
gc::TenuredHeap, shape, group)));
if (!obj)
return nullptr;
@ -684,7 +680,22 @@ ClonedBlockObject::clone(JSContext* cx, Handle<ClonedBlockObject*> clonedBlock)
StaticBlockObject*
StaticBlockObject::create(ExclusiveContext* cx)
{
return NewObjectWithNullTaggedProto<StaticBlockObject>(cx, TenuredObject, BaseShape::DELEGATE);
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &BlockObject::class_,
TaggedProto(nullptr)));
if (!group)
return nullptr;
RootedShape emptyBlockShape(cx);
emptyBlockShape = EmptyShape::getInitialShape(cx, &BlockObject::class_, TaggedProto(nullptr),
FINALIZE_KIND, BaseShape::DELEGATE);
if (!emptyBlockShape)
return nullptr;
JSObject* obj = JSObject::create(cx, FINALIZE_KIND, gc::TenuredHeap, emptyBlockShape, group);
if (!obj)
return nullptr;
return &obj->as<StaticBlockObject>();
}
/* static */ Shape*
@ -882,13 +893,22 @@ js::CloneNestedScopeObject(JSContext* cx, HandleObject enclosingScope, Handle<Ne
/* static */ UninitializedLexicalObject*
UninitializedLexicalObject::create(JSContext* cx, HandleObject enclosing)
{
UninitializedLexicalObject* obj =
NewObjectWithNullTaggedProto<UninitializedLexicalObject>(cx, GenericObject,
BaseShape::DELEGATE);
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
if (!group)
return nullptr;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &class_, TaggedProto(nullptr),
FINALIZE_KIND));
if (!shape)
return nullptr;
RootedObject obj(cx, JSObject::create(cx, FINALIZE_KIND, gc::DefaultHeap, shape, group));
if (!obj)
return nullptr;
obj->setEnclosingScope(enclosing);
return obj;
obj->as<ScopeObject>().setEnclosingScope(enclosing);
return &obj->as<UninitializedLexicalObject>();
}
static void
@ -1025,14 +1045,7 @@ ScopeIter::ScopeIter(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc
void
ScopeIter::incrementStaticScopeIter()
{
// If settled on a non-syntactic static scope, only increment ssi_ once
// we've iterated through all the non-syntactic dynamic ScopeObjects.
if (ssi_.type() == StaticScopeIter<CanGC>::NonSyntactic) {
if (!hasNonSyntacticScopeObject())
ssi_++;
} else {
ssi_++;
}
ssi_++;
// For named lambdas, DeclEnvObject scopes are always attached to their
// CallObjects. Skip it here, as they are special cased in users of
@ -1059,7 +1072,7 @@ ScopeIter::settle()
frame_ = NullFramePtr();
#ifdef DEBUG
if (!ssi_.done() && hasAnyScopeObject()) {
if (!ssi_.done() && hasScopeObject()) {
switch (ssi_.type()) {
case StaticScopeIter<CanGC>::Function:
MOZ_ASSERT(scope_->as<CallObject>().callee().nonLazyScript() == ssi_.funScript());
@ -1073,9 +1086,6 @@ ScopeIter::settle()
case StaticScopeIter<CanGC>::Eval:
MOZ_ASSERT(scope_->as<CallObject>().isForEval());
break;
case StaticScopeIter<CanGC>::NonSyntactic:
MOZ_ASSERT(!IsSyntacticScope(scope_));
break;
case StaticScopeIter<CanGC>::NamedLambda:
MOZ_CRASH("named lambda static scopes should have been skipped");
}
@ -1086,7 +1096,7 @@ ScopeIter::settle()
ScopeIter&
ScopeIter::operator++()
{
if (hasAnyScopeObject()) {
if (hasScopeObject()) {
scope_ = &scope_->as<ScopeObject>().enclosingScope();
if (scope_->is<DeclEnvObject>())
scope_ = &scope_->as<DeclEnvObject>().enclosingScope();
@ -1112,8 +1122,6 @@ ScopeIter::type() const
return With;
case StaticScopeIter<CanGC>::Eval:
return Eval;
case StaticScopeIter<CanGC>::NonSyntactic:
return NonSyntactic;
case StaticScopeIter<CanGC>::NamedLambda:
MOZ_CRASH("named lambda static scopes should have been skipped");
default:
@ -1124,7 +1132,7 @@ ScopeIter::type() const
ScopeObject&
ScopeIter::scope() const
{
MOZ_ASSERT(hasAnyScopeObject());
MOZ_ASSERT(hasScopeObject());
return scope_->as<ScopeObject>();
}
@ -1143,8 +1151,6 @@ ScopeIter::maybeStaticScope() const
return &staticWith();
case StaticScopeIter<CanGC>::Eval:
return &staticEval();
case StaticScopeIter<CanGC>::NonSyntactic:
return &staticNonSyntactic();
case StaticScopeIter<CanGC>::NamedLambda:
MOZ_CRASH("named lambda static scopes should have been skipped");
default:
@ -1744,7 +1750,7 @@ const DebugScopeProxy DebugScopeProxy::singleton;
DebugScopeObject::create(JSContext* cx, ScopeObject& scope, HandleObject enclosing)
{
MOZ_ASSERT(scope.compartment() == cx->compartment());
MOZ_ASSERT(!enclosing->is<ScopeObject>());
MOZ_ASSERT(!IsSyntacticScope(enclosing));
RootedValue priv(cx, ObjectValue(scope));
JSObject* obj = NewProxyObject(cx, &DebugScopeProxy::singleton, priv,
@ -2006,7 +2012,7 @@ DebugScopes::addDebugScope(JSContext* cx, ScopeObject& scope, DebugScopeObject&
DebugScopeObject*
DebugScopes::hasDebugScope(JSContext* cx, const ScopeIter& si)
{
MOZ_ASSERT(!si.hasSyntacticScopeObject());
MOZ_ASSERT(!si.hasScopeObject());
DebugScopes* scopes = cx->compartment()->debugScopes;
if (!scopes)
@ -2022,7 +2028,7 @@ DebugScopes::hasDebugScope(JSContext* cx, const ScopeIter& si)
bool
DebugScopes::addDebugScope(JSContext* cx, const ScopeIter& si, DebugScopeObject& debugScope)
{
MOZ_ASSERT(!si.hasSyntacticScopeObject());
MOZ_ASSERT(!si.hasScopeObject());
MOZ_ASSERT(cx->compartment() == debugScope.compartment());
MOZ_ASSERT_IF(si.withinInitialFrame() && si.initialFrame().isFunctionFrame(),
!si.initialFrame().callee()->isGenerator());
@ -2240,7 +2246,7 @@ DebugScopes::updateLiveScopes(JSContext* cx)
continue;
for (ScopeIter si(cx, frame, i.pc()); si.withinInitialFrame(); ++si) {
if (si.hasSyntacticScopeObject()) {
if (si.hasScopeObject()) {
MOZ_ASSERT(si.scope().compartment() == cx->compartment());
DebugScopes* scopes = ensureCompartmentData(cx);
if (!scopes)
@ -2358,7 +2364,7 @@ GetDebugScopeForScope(JSContext* cx, const ScopeIter& si)
static DebugScopeObject*
GetDebugScopeForMissing(JSContext* cx, const ScopeIter& si)
{
MOZ_ASSERT(!si.hasSyntacticScopeObject() && si.canHaveSyntacticScopeObject());
MOZ_ASSERT(!si.hasScopeObject() && si.canHaveScopeObject());
if (DebugScopeObject* debugScope = DebugScopes::hasDebugScope(cx, si))
return debugScope;
@ -2425,8 +2431,6 @@ GetDebugScopeForMissing(JSContext* cx, const ScopeIter& si)
case ScopeIter::With:
case ScopeIter::Eval:
MOZ_CRASH("should already have a scope");
case ScopeIter::NonSyntactic:
MOZ_CRASH("non-syntactic scopes cannot be synthesized");
}
if (!debugScope)
return nullptr;
@ -2441,11 +2445,11 @@ static JSObject*
GetDebugScopeForNonScopeObject(const ScopeIter& si)
{
JSObject& enclosing = si.enclosingScope();
MOZ_ASSERT(!enclosing.is<ScopeObject>());
MOZ_ASSERT(!IsSyntacticScope(&enclosing));
#ifdef DEBUG
JSObject* o = &enclosing;
while ((o = o->enclosingScope()))
MOZ_ASSERT(!o->is<ScopeObject>());
MOZ_ASSERT(!IsSyntacticScope(o));
#endif
return &enclosing;
}
@ -2458,10 +2462,10 @@ GetDebugScope(JSContext* cx, const ScopeIter& si)
if (si.done())
return GetDebugScopeForNonScopeObject(si);
if (si.hasAnyScopeObject())
if (si.hasScopeObject())
return GetDebugScopeForScope(cx, si);
if (si.canHaveSyntacticScopeObject())
if (si.canHaveScopeObject())
return GetDebugScopeForMissing(cx, si);
ScopeIter copy(cx, si);
@ -2510,7 +2514,8 @@ js::GetObjectEnvironmentObjectForFunction(JSFunction* fun)
bool
js::CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
HandleObject dynamicTerminatingScope,
MutableHandleObject dynamicScopeObj)
MutableHandleObject dynamicScopeObj,
MutableHandleObject staticScopeObj)
{
#ifdef DEBUG
for (size_t i = 0; i < scopeChain.length(); ++i) {
@ -2540,55 +2545,12 @@ js::CreateScopeObjectsForScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
}
dynamicScopeObj.set(dynamicEnclosingScope);
staticScopeObj.set(staticEnclosingScope);
return true;
}
bool
js::HasNonSyntacticStaticScopeChain(JSObject* staticScope)
{
for (StaticScopeIter<NoGC> ssi(staticScope); !ssi.done(); ssi++) {
// If we hit a function scope, we can short circuit the logic, as
// scripts cache whether they are under a non-syntactic scope.
if (ssi.type() == StaticScopeIter<NoGC>::Function)
return ssi.funScript()->hasNonSyntacticScope();
if (ssi.type() == StaticScopeIter<NoGC>::NonSyntactic)
return true;
}
return false;
}
#ifdef DEBUG
void
js::DumpStaticScopeChain(JSScript* script)
{
JSObject* enclosingScope = script->enclosingStaticScope();
for (StaticScopeIter<NoGC> ssi(enclosingScope); !ssi.done(); ssi++) {
switch (ssi.type()) {
case StaticScopeIter<NoGC>::Function:
fprintf(stdout, "function");
break;
case StaticScopeIter<NoGC>::Block:
fprintf(stdout, "block");
break;
case StaticScopeIter<NoGC>::With:
fprintf(stdout, "with");
break;
case StaticScopeIter<NoGC>::NamedLambda:
fprintf(stdout, "named lambda");
break;
case StaticScopeIter<NoGC>::Eval:
fprintf(stdout, "eval");
break;
case StaticScopeIter<NoGC>::NonSyntactic:
fprintf(stdout, "non-syntactic");
break;
}
fprintf(stdout, " -> ");
}
fprintf(stdout, "global\n");
}
typedef HashSet<PropertyName*> PropertyNameSet;
static bool
@ -2621,7 +2583,7 @@ RemoveReferencedNames(JSContext* cx, HandleScript script, PropertyNameSet& remai
case JSOP_GETGNAME:
case JSOP_SETGNAME:
case JSOP_STRICTSETGNAME:
if (script->hasNonSyntacticScope())
if (script->hasPollutedGlobalScope())
name = script->getName(pc);
else
name = nullptr;

Some files were not shown because too many files have changed in this diff Show More