mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c. a=merge
CLOSED TREE
This commit is contained in:
commit
725ca1c6fb
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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]
|
||||
|
15
docshell/test/browser/browser_multiple_pushState.js
Normal file
15
docshell/test/browser/browser_multiple_pushState.js
Normal 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);
|
||||
});
|
||||
});
|
14
docshell/test/browser/file_multiple_pushState.html
Normal file
14
docshell/test/browser/file_multiple_pushState.html
Normal 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>
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -2496,6 +2496,12 @@ SourceMediaStream::FinishAddTracks()
|
||||
}
|
||||
}
|
||||
|
||||
StreamBuffer::Track*
|
||||
SourceMediaStream::FindTrack(TrackID aID)
|
||||
{
|
||||
return mBuffer.FindTrack(aID);
|
||||
}
|
||||
|
||||
void
|
||||
SourceMediaStream::ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -424,6 +424,8 @@ public:
|
||||
*/
|
||||
static bool IsInCompositorThread();
|
||||
|
||||
nsIWidget* GetWidget() { return mWidget; }
|
||||
|
||||
protected:
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
virtual ~CompositorParent();
|
||||
|
@ -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
|
||||
|
@ -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"));
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()))
|
||||
{
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
class ScopeObject;
|
||||
class StaticEvalObject;
|
||||
|
||||
namespace frontend {
|
||||
|
||||
|
@ -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());
|
||||
|
@ -1699,6 +1699,7 @@ enum FunctionSyntaxKind
|
||||
Arrow,
|
||||
Method,
|
||||
ClassConstructor,
|
||||
DerivedClassConstructor,
|
||||
Getter,
|
||||
Setter
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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*
|
||||
|
@ -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) {
|
||||
|
@ -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');
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
|
@ -285,6 +285,7 @@ class JSAPITest
|
||||
return nullptr;
|
||||
JS_SetErrorReporter(rt, &reportError);
|
||||
setNativeStackQuota(rt);
|
||||
JS::RuntimeOptionsRef(rt).setVarObjFix(true);
|
||||
return rt;
|
||||
}
|
||||
|
||||
|
271
js/src/jsapi.cpp
271
js/src/jsapi.cpp
@ -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)
|
||||
|
@ -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
|
||||
|
245
js/src/jsfun.cpp
245
js/src/jsfun.cpp
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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>
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
25
js/src/tests/ecma_5/Function/Function-with-eval.js
Normal file
25
js/src/tests/ecma_5/Function/Function-with-eval.js
Normal 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");
|
37
js/src/tests/ecma_6/Class/derivedConstructorDisabled.js
Normal file
37
js/src/tests/ecma_6/Class/derivedConstructorDisabled.js
Normal 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");
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user