--- a/accessible/interfaces/nsIAccessiblePivot.idl
+++ b/accessible/interfaces/nsIAccessiblePivot.idl
@@ -186,17 +186,17 @@ interface nsIAccessiblePivot : nsISuppor
* @param aObserver [in] the observer object to remove from being notified.
*/
void removeObserver(in nsIAccessiblePivotObserver aObserver);
};
/**
* An observer interface for pivot changes.
*/
-[scriptable, uuid(b6508c5e-c081-467d-835c-613eedf9ee9b)]
+[scriptable, uuid(6006e502-3861-49bd-aba1-fa6d2e74e237)]
interface nsIAccessiblePivotObserver : nsISupports
{
/**
* Called when the pivot changes.
*
* @param aPivot [in] the pivot that has changed.
* @param aOldAccessible [in] the old pivot position before the change,
* or null.
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -328,16 +328,17 @@ var shell = {
window.addEventListener('MozApplicationManifest', this);
window.addEventListener('mozfullscreenchange', this);
window.addEventListener('MozAfterPaint', this);
window.addEventListener('sizemodechange', this);
window.addEventListener('unload', this);
this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
this.contentBrowser.addEventListener('mozbrowserselectionchange', this, true);
this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true);
+ this.contentBrowser.addEventListener('mozbrowsertouchcarettap', this, true);
CustomEventManager.init();
WebappsHelper.init();
UserAgentOverrides.init();
IndexedDBPromptHelper.init();
CaptivePortalLoginHelper.init();
this.contentBrowser.src = homeURL;
@@ -356,16 +357,17 @@ var shell = {
window.removeEventListener('keypress', this, true);
window.removeEventListener('keyup', this, true);
window.removeEventListener('MozApplicationManifest', this);
window.removeEventListener('mozfullscreenchange', this);
window.removeEventListener('sizemodechange', this);
this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
this.contentBrowser.removeEventListener('mozbrowserselectionchange', this, true);
this.contentBrowser.removeEventListener('mozbrowserscrollviewchange', this, true);
+ this.contentBrowser.removeEventListener('mozbrowsertouchcarettap', this, true);
ppmm.removeMessageListener("content-handler", this);
UserAgentOverrides.uninit();
IndexedDBPromptHelper.uninit();
},
// If this key event actually represents a hardware button, filter it here
// and send a mozChromeEvent with detail.type set to xxx-button-press or
@@ -503,16 +505,22 @@ var shell = {
this.notifyContentStart();
break;
case 'mozbrowserscrollviewchange':
this.sendChromeEvent({
type: 'scrollviewchange',
detail: evt.detail,
});
break;
+ case 'mozbrowsertouchcarettap':
+ this.sendChromeEvent({
+ type: 'touchcarettap',
+ detail: evt.detail,
+ });
+ break;
case 'mozbrowserselectionchange':
// The mozbrowserselectionchange event, may have crossed the chrome-content boundary.
// This event always dispatch to shell.js. But the offset we got from this event is
// based on tab's coordinate. So get the actual offsets between shell and evt.target.
let elt = evt.target;
let win = elt.ownerDocument.defaultView;
let offsetX = win.mozInnerScreenX - window.mozInnerScreenX;
let offsetY = win.mozInnerScreenY - window.mozInnerScreenY;
--- a/content/base/public/nsIDOMParser.idl
+++ b/content/base/public/nsIDOMParser.idl
@@ -14,17 +14,17 @@ interface nsIGlobalObject;
/**
* The nsIDOMParser interface is a non-SAX interface that can be used
* to parse a string or byte stream containing XML or HTML content
* to a DOM document. Parsing is always synchronous - a document is always
* returned from the parsing methods. This is as opposed to loading and
* parsing with the XMLHttpRequest interface, which can be used for
* asynchronous (callback-based) loading.
*/
-[uuid(5677f36e-1842-4c6f-a39c-2e5576ab8b40)]
+[uuid(70b9600e-8622-4c93-9ad8-22c28058dc44)]
interface nsIDOMParser : nsISupports
{
/**
* The string passed in is parsed into a DOM document.
*
* @param str The UTF16 string to be parsed
* @param contentType The content type of the string (see parseFromStream)
* @returns The DOM document created as a result of parsing the
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -1828,23 +1828,16 @@ HTMLInputElement::SetValue(const nsAStri
//
// NOTE: this is currently quite expensive work (too much string
// manipulation). We should probably optimize that.
nsAutoString currentValue;
GetValue(currentValue);
SetValueInternal(aValue, false, true);
- if (mType == NS_FORM_INPUT_RANGE) {
- nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
- if (frame) {
- frame->UpdateForValueChange();
- }
- }
-
if (mFocusedValue.Equals(currentValue)) {
GetValue(mFocusedValue);
}
} else {
SetValueInternal(aValue, false, true);
}
}
}
@@ -2843,16 +2836,21 @@ HTMLInputElement::SetValueInternal(const
if (mType == NS_FORM_INPUT_NUMBER) {
// This has to happen before OnValueChanged is called because that
// method needs the new value of our frame's anon text control.
nsNumberControlFrame* numberControlFrame =
do_QueryFrame(GetPrimaryFrame());
if (numberControlFrame) {
numberControlFrame->SetValueOfAnonTextControl(value);
}
+ } else if (mType == NS_FORM_INPUT_RANGE) {
+ nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
+ if (frame) {
+ frame->UpdateForValueChange();
+ }
}
if (!mParserCreating) {
OnValueChanged(true);
}
// else DoneCreatingElement calls us again once mParserCreating is false
}
if (mType == NS_FORM_INPUT_COLOR) {
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -221,16 +221,22 @@ BrowserElementChild.prototype = {
/* useCapture = */ false,
/* wantsUntrusted = */ false);
addEventListener('scrollviewchange',
this._ScrollViewChangeHandler.bind(this),
/* useCapture = */ false,
/* wantsUntrusted = */ false);
+ addEventListener('touchcarettap',
+ this._touchCaretTapHandler.bind(this),
+ /* useCapture = */ false,
+ /* wantsUntrusted = */ false);
+
+
// This listens to unload events from our message manager, but /not/ from
// the |content| window. That's because the window's unload event doesn't
// bubble, and we're not using a capturing listener. If we'd used
// useCapture == true, we /would/ hear unload events from the window, which
// is not what we want!
addEventListener('unload',
this._unloadHandler.bind(this),
/* useCapture = */ false,
@@ -626,16 +632,21 @@ BrowserElementChild.prototype = {
if (lang) {
meta.lang = lang;
}
sendAsyncMsg('metachange', meta);
},
+ _touchCaretTapHandler: function(e) {
+ e.stopPropagation();
+ sendAsyncMsg('touchcarettap');
+ },
+
_ScrollViewChangeHandler: function(e) {
e.stopPropagation();
let detail = {
state: e.state,
scrollX: e.scrollX,
scrollY: e.scrollY,
};
sendAsyncMsg('scrollviewchange', detail);
--- a/dom/browser-element/BrowserElementParent.jsm
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -253,17 +253,18 @@ BrowserElementParent.prototype = {
"got-can-go-forward": this._gotDOMRequestResult,
"fullscreen-origin-change": this._remoteFullscreenOriginChange,
"rollback-fullscreen": this._remoteFrameFullscreenReverted,
"exit-fullscreen": this._exitFullscreen,
"got-visible": this._gotDOMRequestResult,
"visibilitychange": this._childVisibilityChange,
"got-set-input-method-active": this._gotDOMRequestResult,
"selectionchange": this._handleSelectionChange,
- "scrollviewchange": this._handleScrollViewChange
+ "scrollviewchange": this._handleScrollViewChange,
+ "touchcarettap": this._handleTouchCaretTap
};
let mmSecuritySensitiveCalls = {
"showmodalprompt": this._handleShowModalPrompt,
"contextmenu": this._fireCtxMenuEvent,
"securitychange": this._fireEventFromMsg,
"locationchange": this._fireEventFromMsg,
"iconchange": this._fireEventFromMsg,
@@ -501,16 +502,22 @@ BrowserElementParent.prototype = {
},
_handleScrollViewChange: function(data) {
let evt = this._createEvent("scrollviewchange", data.json,
/* cancelable = */ false);
this._frameElement.dispatchEvent(evt);
},
+ _handleTouchCaretTap: function(data) {
+ let evt = this._createEvent("touchcarettap", data.json,
+ /* cancelable = */ false);
+ this._frameElement.dispatchEvent(evt);
+ },
+
_createEvent: function(evtName, detail, cancelable) {
// This will have to change if we ever want to send a CustomEvent with null
// detail. For now, it's OK.
if (detail !== undefined && detail !== null) {
detail = Cu.cloneInto(detail, this._window);
return new this._window.CustomEvent('mozbrowser' + evtName,
{ bubbles: true,
cancelable: cancelable,
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -148,16 +148,18 @@ const int32_t kStorageProgressGranularit
const char kSavepointClause[] = "SAVEPOINT sp;";
const fallible_t fallible = fallible_t();
const uint32_t kFileCopyBufferSize = 32768;
const char kJournalDirectoryName[] = "journals";
+const char kFileManagerDirectoryNameSuffix[] = ".files";
+
const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled";
#define IDB_PREFIX "indexedDB"
#ifdef MOZ_CHILD_PERMISSIONS
const char kPermissionString[] = IDB_PREFIX;
#endif // MOZ_CHILD_PERMISSIONS
@@ -5414,29 +5416,33 @@ ConvertFileIdsToArray(const nsAString& a
aResult.AppendElement(id);
}
return NS_OK;
}
bool
GetDatabaseBaseFilename(const nsAString& aFilename,
- nsAString& aDatabaseBaseFilename)
+ nsDependentSubstring& aDatabaseBaseFilename)
{
MOZ_ASSERT(!aFilename.IsEmpty());
+ MOZ_ASSERT(aDatabaseBaseFilename.IsEmpty());
NS_NAMED_LITERAL_STRING(sqlite, ".sqlite");
- if (!StringEndsWith(aFilename, sqlite)) {
+ if (!StringEndsWith(aFilename, sqlite) ||
+ aFilename.Length() == sqlite.Length()) {
return false;
}
- aDatabaseBaseFilename =
- Substring(aFilename, 0, aFilename.Length() - sqlite.Length());
-
+ MOZ_ASSERT(aFilename.Length() > sqlite.Length());
+
+ aDatabaseBaseFilename.Rebind(aFilename,
+ 0,
+ aFilename.Length() - sqlite.Length());
return true;
}
nsresult
ConvertBlobsToActors(PBackgroundParent* aBackgroundActor,
FileManager* aFileManager,
const nsTArray<StructuredCloneFile>& aFiles,
FallibleTArray<PBlobParent*>& aActors,
@@ -9145,16 +9151,22 @@ QuotaClient::NoteBackgroundThread(nsIEve
}
mozilla::dom::quota::Client::Type
QuotaClient::GetType()
{
return QuotaClient::IDB;
}
+struct FileManagerInitInfo
+{
+ nsCOMPtr<nsIFile> mDirectory;
+ nsCOMPtr<nsIFile> mDatabaseFile;
+};
+
nsresult
QuotaClient::InitOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
UsageInfo* aUsageInfo)
{
AssertIsOnIOThread();
@@ -9165,141 +9177,222 @@ QuotaClient::InitOrigin(PersistenceType
return rv;
}
// We need to see if there are any files in the directory already. If they
// are database files then we need to cleanup stored files (if it's needed)
// and also get the usage.
nsAutoTArray<nsString, 20> subdirsToProcess;
- nsAutoTArray<nsCOMPtr<nsIFile> , 20> unknownFiles;
+ nsTArray<nsCOMPtr<nsIFile>> unknownFiles;
nsTHashtable<nsStringHashKey> validSubdirs(20);
+ nsAutoTArray<FileManagerInitInfo, 20> initInfos;
nsCOMPtr<nsISimpleEnumerator> entries;
rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+ const NS_ConvertASCIItoUTF16 filesSuffix(kFileManagerDirectoryNameSuffix);
+
bool hasMore;
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
- hasMore && (!aUsageInfo || !aUsageInfo->Canceled())) {
+ hasMore &&
+ (!aUsageInfo || !aUsageInfo->Canceled())) {
nsCOMPtr<nsISupports> entry;
rv = entries->GetNext(getter_AddRefs(entry));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
MOZ_ASSERT(file);
nsString leafName;
rv = file->GetLeafName(leafName);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
- continue;
- }
-
- if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
- continue;
- }
bool isDirectory;
rv = file->IsDirectory(&isDirectory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (isDirectory) {
- if (!validSubdirs.GetEntry(leafName)) {
+ if (!StringEndsWith(leafName, filesSuffix) ||
+ !validSubdirs.GetEntry(leafName)) {
subdirsToProcess.AppendElement(leafName);
}
continue;
}
- nsString dbBaseFilename;
+ // Skip SQLite and Desktop Service Store (.DS_Store) files.
+ // Desktop Service Store file is only used on Mac OS X, but the profile
+ // can be shared across different operating systems, so we check it on
+ // all platforms.
+ if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal")) ||
+ leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
+ continue;
+ }
+
+ nsDependentSubstring dbBaseFilename;
if (!GetDatabaseBaseFilename(leafName, dbBaseFilename)) {
unknownFiles.AppendElement(file);
continue;
}
+ nsString fmDirectoryBaseName = dbBaseFilename + filesSuffix;
+
nsCOMPtr<nsIFile> fmDirectory;
rv = directory->Clone(getter_AddRefs(fmDirectory));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- rv = fmDirectory->Append(dbBaseFilename);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = FileManager::InitDirectory(fmDirectory, file, aPersistenceType, aGroup,
+ rv = fmDirectory->Append(fmDirectoryBaseName);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ FileManagerInitInfo* initInfo = initInfos.AppendElement();
+ initInfo->mDirectory.swap(fmDirectory);
+ initInfo->mDatabaseFile.swap(file);
+
+ validSubdirs.PutEntry(fmDirectoryBaseName);
+ }
+
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ for (uint32_t count = subdirsToProcess.Length(), i = 0; i < count; i++) {
+ const nsString& subdirName = subdirsToProcess[i];
+
+ // If the directory has the correct suffix then it must exist in
+ // validSubdirs.
+ if (StringEndsWith(subdirName, filesSuffix)) {
+ if (NS_WARN_IF(!validSubdirs.GetEntry(subdirName))) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ continue;
+ }
+
+ // The directory didn't have the right suffix but we might need to rename
+ // it. Check to see if we have a database that references this directory.
+ nsString subdirNameWithSuffix = subdirName + filesSuffix;
+ if (!validSubdirs.GetEntry(subdirNameWithSuffix)) {
+ // Windows doesn't allow a directory to end with a dot ('.'), so we have
+ // to check that possibility here too.
+ // We do this on all platforms, because the origin directory may have
+ // been created on Windows and now accessed on different OS.
+ subdirNameWithSuffix = subdirName + NS_LITERAL_STRING(".") + filesSuffix;
+ if (NS_WARN_IF(!validSubdirs.GetEntry(subdirNameWithSuffix))) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ }
+
+ // We do have a database that uses this directory so we should rename it
+ // now. However, first check to make sure that we're not overwriting
+ // something else.
+ nsCOMPtr<nsIFile> subdir;
+ rv = directory->Clone(getter_AddRefs(subdir));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ rv = subdir->Append(subdirNameWithSuffix);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ bool exists;
+ rv = subdir->Exists(&exists);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (exists) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ }
+
+ rv = directory->Clone(getter_AddRefs(subdir));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ rv = subdir->Append(subdirName);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ DebugOnly<bool> isDirectory;
+ MOZ_ASSERT(NS_SUCCEEDED(subdir->IsDirectory(&isDirectory)));
+ MOZ_ASSERT(isDirectory);
+
+ rv = subdir->RenameTo(nullptr, subdirNameWithSuffix);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ }
+
+ for (uint32_t count = initInfos.Length(), i = 0; i < count; i++) {
+ FileManagerInitInfo& initInfo = initInfos[i];
+ MOZ_ASSERT(initInfo.mDirectory);
+ MOZ_ASSERT(initInfo.mDatabaseFile);
+
+ rv = FileManager::InitDirectory(initInfo.mDirectory,
+ initInfo.mDatabaseFile,
+ aPersistenceType,
+ aGroup,
aOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- if (aUsageInfo) {
+ if (aUsageInfo && !aUsageInfo->Canceled()) {
int64_t fileSize;
- rv = file->GetFileSize(&fileSize);
+ rv = initInfo.mDatabaseFile->GetFileSize(&fileSize);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(fileSize >= 0);
aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
uint64_t usage;
- rv = FileManager::GetUsage(fmDirectory, &usage);
+ rv = FileManager::GetUsage(initInfo.mDirectory, &usage);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
aUsageInfo->AppendToFileUsage(usage);
}
-
- validSubdirs.PutEntry(dbBaseFilename);
- }
-
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- for (uint32_t i = 0; i < subdirsToProcess.Length(); i++) {
- const nsString& subdir = subdirsToProcess[i];
- if (NS_WARN_IF(!validSubdirs.GetEntry(subdir))) {
- return NS_ERROR_UNEXPECTED;
- }
- }
-
- for (uint32_t i = 0; i < unknownFiles.Length(); i++) {
+ }
+
+ // We have to do this after file manager initialization.
+ for (uint32_t count = unknownFiles.Length(), i = 0; i < count; i++) {
nsCOMPtr<nsIFile>& unknownFile = unknownFiles[i];
- // Some temporary SQLite files could disappear, so we have to check if the
- // unknown file still exists.
+ // Some temporary SQLite files could disappear during file manager
+ // initialization, so we have to check if the unknown file still exists.
bool exists;
rv = unknownFile->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (exists) {
- nsString leafName;
- unknownFile->GetLeafName(leafName);
-
- // The journal file may exists even after db has been correctly opened.
- if (NS_WARN_IF(!StringEndsWith(leafName,
- NS_LITERAL_STRING(".sqlite-journal")))) {
- return NS_ERROR_UNEXPECTED;
- }
+ return NS_ERROR_UNEXPECTED;
}
}
return NS_OK;
}
nsresult
QuotaClient::GetUsageForOrigin(PersistenceType aPersistenceType,
@@ -11169,17 +11262,19 @@ OpenDatabaseOp::DoDatabaseWork()
}
nsCOMPtr<nsIFile> fmDirectory;
rv = dbDirectory->Clone(getter_AddRefs(fmDirectory));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- rv = fmDirectory->Append(filename);
+ const NS_ConvertASCIItoUTF16 filesSuffix(kFileManagerDirectoryNameSuffix);
+
+ rv = fmDirectory->Append(filename + filesSuffix);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<mozIStorageConnection> connection;
rv = CreateDatabaseConnection(dbFile,
fmDirectory,
databaseName,
@@ -12655,17 +12750,20 @@ VersionChangeOp::RunOnIOThread()
}
nsCOMPtr<nsIFile> fmDirectory;
rv = directory->Clone(getter_AddRefs(fmDirectory));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- rv = fmDirectory->Append(mDeleteDatabaseOp->mDatabaseFilenameBase);
+ const NS_ConvertASCIItoUTF16 filesSuffix(kFileManagerDirectoryNameSuffix);
+
+ rv = fmDirectory->Append(mDeleteDatabaseOp->mDatabaseFilenameBase +
+ filesSuffix);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = fmDirectory->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -111,17 +111,17 @@ skip-if = (buildapp == 'b2g' && toolkit
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_archive.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_simple.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_worker_crash.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_worker_xhr_post.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
+skip-if = ((buildapp == 'b2g' && toolkit != 'gonk') || (e10s && toolkit == 'windows')) # Bug 931116
[test_blocked_order.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_bug937006.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_clear.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_complex_keyPaths.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..db3cfe62464e8f50d11664578c879c8af7c45014
GIT binary patch
literal 8029
zc$}?S2{@E%8`dIi(y1hkOr1JZgtCmuc63N~NrYii82dJsImVFVrzEK+lx-{t*%CvR
z8QGF$X0m6UjGZRS*rzc+=`SZ8=I=W1T<>+wb$##L&->i(H{bny&#j}rY4dirrO|#7
ztjxAzY-QtPgS$Gqn87SWFY9e%+r%Iq)e|Kh)pJAaVB4^HY6BbF=6#FnbiN`Ce21`i
z1%i`>3)~v+YT@9z4E76Y9Wdi4C8d>M2Y(E9-O9z${>ui5XU28^FU+HBVv5*XxSE-p
zxte_i-?J9@=y%!kuL*8#er<WvN7f^v{ySXBb#c!~fWRQ|X|R}-o2wHXX5r#$1~vb}
z(a1j^;=a#^z7$U9UFm(&mgSp3<|o66z@6=^T`j%_U7FtorMA>L8XNGkITcbV&5<po
zdUIwc3oh&Jvu!QV*?rDxqhNkjnkBLSm}|Fht-XUxrgc47%TVG<v>md4!}y(YOnLE*
zasVY%<)hn&^1D<iA!UPGWbN@G0(c;X9zE*SVs9XCWRnyBenE?N5y#z8og?0A*B`EU
zugaWQff0JV*MAlsH#%eYsX;-$I={Bv2XkDO@kf7fKU7?sIopK6EDX<#qNawzedarh
zr<vn@g7jcA@gs9As90{U2JMd{85Ot6-AUTO_RnJs>NYkF$Ok!^;1G!PCOcWgZpl$l
zZhSDVGIB~kr>;fPU`I`=*>j^*VUYmr)$+91qUQ%g(ooVE4M>K2|K=Sv*u%mk9I!EL
zbhAenSE{095lu_Hz{e5hSjb((Qv|3D2nw|k1B&>Mqjq5XxbA+uBiK?Jo5f2qG>z~{
z%9^7cP9p--d=zFZ|D2$7d(LFZcqjyY#7a>v3<DzT^j-Jpkl&;XR+1Y!l|YXWdr_BE
zKK!;V4SoA{zk`n9wr4e|if;DSDTPU)h{yR&v5`q#Pm|_HBR<xOx=p(yhLF)X6eIf=
zBtT=jb$YsXlhM|@M}5Xouf@@{Pa*KPdFNA*M1$8D_;n=6CKqokvSoCrKVH{ln{6tI
z%nYKQetg=-u^1mEWQvQBJDxl2kr!_+JO>$KhsKy}4>9#kc{wlC)Fjqga}!(5(bwkb
zBm=?hx=Y4%S&7Ehmtb4q6;qL|eo%>AP=e@mE&wxH5u%k5G9h*kO$e^b7V)^AqBl?$
z;+K8ufw{AlrI@5Nc5;f#l)&xSRqIWEo;?=_2smpBxKMM8gU@8f;#qjm(0f&st>|{k
z@GuztEPa#b0jh#6qBkDJ;XE<+F*`tCRFlKDsanOh`)woQSVs2q7gr8JQuZ~L`p-sY
zp5@7y)Ni+^N)$%Ms96dFeN2d<2L08v?)SP$y7Jdb%&jKX5?##VU%HD&4$0cj(9+LC
z>ZWkb#EV{KiDL<I87(!LsJ!1S0}8ftw0dPA=$_M8Uo^}`)ywdDyTv+@bh1dto60JA
z;1we+*<^gvi6-=8L4)uuw`o2pC!wZP&Ej%Op__I5O9TqiHyK`A<+d<}4um*c3eX94
z2Gvd-WpeqxZ~#A$Nsy8DXjHXp0V<c+%#PbYp;5Hp%Bkk0BszVEPq}W$bgogbRbf*H
z@bo*nDVV$NB3qL7Y~zzG4!M3vzsueV8Sx&Xg|rVqybQ&|l_b)88;x#tyv-PR$Y)0G
z6H3r}N>{^;-9I)oiX7=L^PgzbbsU==o$9rF>PO7h!lABTLKTgv6KAwdA0O8jz@SGH
zc;ZIG1O0%Q8g9pqH~e_XNr6cy258LaK}X5T$yXu?gBK+z<U^HU)XYxNSE}b^5{>4E
z<^m~H0PI<YZ$ZIsCbO@!%q{~#HJXlXY;}1MP&n1uqd?-c!?qwN-#46=4~!@bj;6vs
zr0d<nJVMQrG(K%w<6pZpn4%&u68UA$%&cNIp4UDnzEl6mkbM##_d36OB8-usKJ;5>
z)s2VT51vN5>|STty%%2fIhS^ATxXfC{)GtlYQ=R{{a!tx+MosAy3Vo-hDWU1PH?RC
zR9hM+Y6LZ9`VOzN>afM!6YC_t&Fd_Cl6H?J()!T<B57gTERnXICDK}pH+<93^e9bb
zzO-<p&?1SO7Wc7hQA4l0SeUt5K+Ug-Sh?EUeU`;$PFX$T;`~k){qJ8?FB9A6Po@iH
zpxRzZjRaKN899A0{KWA<z{CEDrkbaWeg)H^ei&W7vAYxu)q1n7SoOiy_f;B)?G?Z#
zpv|6a{%Y!q$v1>`{Kn4cr-wP^M86f7QaKpEaR2m>&OP~r91|Gfo{>Sew`J3v7ap!*
z7DEBbs=DWk;xafl`JY5>7t}lzb~7u$4(?G*rXKMH?^WEkC-lI*Z1&q56)q$pH%530
zUn|{_1#;dW6oIMZY>W6+9Z0$7eK7c#=nVkDhU(8%TvFV)bMrIL{f8`dewUrb?%fXE
z#&Melt(6ihX?Uuo-K<~AP^4~jGt@8GsZDq!wOus%?#;$&D}6GEd@h&BoXIoz)EUC$
z^)ypw#~&kxxg0e$l=PKM=YDo;VEe?&Ug0-8K+FoBZ<M<{I<Ne=`4a5ym$F4}{jx<0
zBqniMQt~v|b@6E6*IXT~9UUxTA}b3QtC}-<OY=vCOVd)}a?06O>|tCrS8_voyjIrM
zQ-+`;5^)4ohrgQM-$3h>ZYr_wxE3K$;e7U2so~9tuCkl~RXTcFRHF?ritNDMMMEmx
z0R>v$*Dc}l5UX53NoRVqpQp^r`$Oh0T5ExS9Y$A01<Lb?S8lHxfKX=aCeeJrevN*D
zPY5?Z^EaB&2<CC652JrHL}8v*NcLKoA}>s0I)V5FyS%x|p-w1jDpQ4tkjSGc(;KJ^
ztAlIZ&rAcPBR&ktc%4Y2hqtHq<B-A4o&D#p+YfYm;ySOWyAm2pCtMB)x16NW%uXFR
zBXpc}O68~!u=e#{p43ioNyoKQTWiEe*|8PICFwJzHaeV+Cbp6vyIR{??KnoaII=f%
zdnF#M4cKAkN`}~vGyG%{s<2{K87lDoJeHY~Ej~Q|X==qaL3>R_Loj40RnC26nkQI>
ziaq{dzRmM`f-|4awO*ykgwY}Ucpi<M!1Bf;$iPh_Pvi6PhxEe!8m74Dm>6Ceq*|Xa
zva|#b_6<2T?5!#kD5R-(;;2vrwlL3;%=;p5!5rh@s4W|t|Ni&{j0}?ymnSj79D$N*
zI5=K<J}NS@Jy@S!*%!}@F%>!4l=wXN(<DQooxg{-Y<jv%D4&w3-io_c=#5PHC8Poq
zbh9KpiKo=h;Oei>7S!CpcV;FO(<i+1a}RdxG!XPlm>F=I6pO9z>I;WgG>x?4$RJP)
z07|u!D((p6KLiE##)%4!*p|U?^+Acc(VPmqwDK-QRro$GQDQdM=M{UMHYoCzqca#E
z`#BsA3?foQPyNB~<P`m;(M&|ZPh~1N`n(wKxpefP#unG&Ec%n~xFCUDl-X_^j5EzN
zVyFJIP%eW~-;}xwdN4B!d|R>ZiDZ9x9SG_s067b>FT^zs+k5^RlZBXc179+YI6(?v
zs7GIzyT{%W*DVxU?Vm-dp0ayN&!LKfA}%Voc(fUFjB|#SW^xpmiWE=wggrVqc=Ce<
zEuTUVYQ>E^3|vwhMa)*<OXZX+<m2>afH5TQOh}bC^L(CO2#g<UGAKmE=w6mDZj1D~
zTj9}Ddc}F6I=NaktajYZo0**jake>0?<_H>zS`j@myd@7_<#&TyMo6%Rl8=O#9w`5
zJ$*{hhcxWXsp$bhI@({sJcUCBK()M{-Pv~N3}P1N@@u>wn^w$Npz2XB&+`1*-q*MD
zo}Q1cxw_E&bPJt0svT9sU0In;=0*?f1Da7L{LKU#kclyK7bug0T?MU98AUIgq!E)d
zo?cRD#Ti4vF8uuzd81kI06kCi4!2N`cGXNt(7jm;yHOC#r6ScJo9?)?Xj|1t_R&-y
z*9SdGDg%h5CdAtV6Qg$%qVR6FdEQIMb?TnNq1@9DwBeLzshJr>Wu_0<Lm^Vg6d%<o
z<d(;m)a{O<50b=D#&RFz5MxybfRaY-gmi-7Qr!~s2=(a?f%$cG`3B~uK{iaCr!AQ3
z4ySct3yqEQM$*r9kX6AV>uH#wyu(=*gkPv!Q;-$me>wDo1>xTfie^Rld!C|M5dL!=
zuDUD;e@LVjE7g*7gDNZ45=*4jRQ`*k2?JRojhn&}Y0Qn^nhnTB8C`i5^wToB+-~@D
zQ9S=#Eui0YTP<2sc^>auT*<O-i=Ppb0!v6pNS;Bg9Dmd8PrGFGmgZ{R);4ZA#CBCi
z)tS<4UvP5bkI<p>$M@=6>xOAwmb@J4y90Yp(>C@5>iBOZ)}6aA1Xul4AQ_NLLOz<7
zwf3oB@K;5S(D^+w?cX14-$poNa+x9DUDg)`C(T8Z!804xfg%z{Q|~{z(-u61Uf#Ec
z{Xn+|>?T9){-)cszw7q+XWhmv>2~IL<q!@kH{Vj`BOBGucri6ZRBYs2>&%&{3=p&i
z=iO63=U0<%*+V0Z5DJ3{^KBpff~WLRr!Gof+EG(u_8gL0OS*}@dLc7bHjfXR<|PL3
zfTX$4Z-xgg^&5(K8uvT0=XLE^>NmKh8x|vBNRL$RB0v$h#!XtNjTk`WKXoWLwqmBx
z<9xKO+1q!w=7mLSO>ONyiEK^Hrl%Ia!I|<a_&jfmbf-^;PsyY&>h=^ic;1pB9jjCm
zIH*EyFjf+MWc5p6#vjdlIGR<JuU{8T7G`g%=!-3Q@%*iEgRVqvt;^e*hVFR52OgU4
z^WkT0WnPZi!0gF*adUe{m3(Jg%u7Xh$;Dn0o|p_P!Z6{x_FRAHN%wM|ln3Ry4-=Y0
zYLuCBIEdaebu;_9p%I^4$=7lL=~T3VONDy)3wlNKJeA<tvEN68e+x9mbZcSAD<#)?
zp{71D(;5zJHNCIR#z`C!z4LAirmVT_h8jH_O5`@kgw6Pn-?b$xv~}8eVF8+lpdPfh
z;pkv&H_mjZLN|pN0OUvl93xVGCtZy%wjFAR;vWf_7RN9aOkv}jKs)t{8pFem>~+oD
z`}k~ah548h3ZBQWAu6mTcoMy#Gj&uh<<G&`z+mZ^B2de#!NjVoiAHlyzwr$o#3~I4
zr_~zJRZg;FokToomtm!eWp(b0`p^|GNZ}7s$*g%iQLpi*)Cb_OQuWQ92SA*_6g`nU
z+y)si@#t1}e4Cw;peHI1+ZpUQcKnlP>~P<Nx`M;46yIm1-clH$uA&E>z)?N<zQIGF
z;&&cS+RoQ7PI_GYQUBBJfn@#}S$x4;4{0B@q=~s`T-5+#)&X)rhzR9%b9tcBKYP|^
zto2HUv}7nFgRaJV2l-r}CC|~1nm{gMpl(vjo97vx&-uKIqLPDL@Y7duQx#S7y(Pdi
zjf_r$egeM9<|C)ItXF2#tz^KfszdU1*1hLL-i1HzxH8_{n2h4BCAT$R?VR%qgy&Oc
z5z~d&TriYV8W6mg9n3SNQQT2AYN7lR2tW)q*uM)9;+<KE6z6sAKRZ4dtT9#hiUcMX
zqs-E-@cO9X3%SlwZe}saQB~ZTrUd??(__buWs>g7G7`{yBz|g7v?aqE^@e;%1&kWm
z$MwqjoQw)~a=JB(LP$+IYl0dWhD<VR@{z5O@rk|<-YMC=(wuoM9(VDWA>&~)dk+fw
zw0s)K<6yh7_7&rl-GpV`UPqPwr`!B)CL`WL<x|v$J?s5qQ554@c^f_lVd-r+B#5QA
zVdpwlS_twYth5k>%9UAaA-uF=p@kp}<YB4rLSczCuYZ%Y3D!tE!V+n8(Qk5nc~L!A
zUX=P-_55PWaLMW|%~fi>VI%*he{zWqeEGJUjry61Z=MnRvS+jg+G@vWCEB?aXn*sM
z*q8mIHGo&UM=OCtehmE8OJZNPd;SmnqhIkC??m68HSt&YO6vz&?JBKI<o6A01zPr)
z*q1$~HDauGm{!Jkv~G-l^qbh1t)Cx;{wKF-C662%e=hXbQgHnZtZvmUZ(!+fc*9qH
z8{4YJ9s6?QZVk-Uy{K<V-SEY4UpJ}sI#cY+ovAgBbafs7?MPoKvhVrXEi51E4=eg_
z`LC|&SLW}&Zt!(0eD>uEe~tWCKNwf$pTql;Tln(q`Ozbi{d2NA7e7bY+1QSK?ymh8
DhVkiI
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_bug1056939.js
@@ -0,0 +1,131 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function testSteps()
+{
+ const dbName1 = "upgrade_test";
+ const dbName2 = "testing.foobar";
+ const dbName3 = "xxxxxxx.xxxxxx";
+
+ clearAllDatabases(continueToNextStepSync);
+ yield undefined;
+
+ installPackagedProfile("bug1056939");
+
+ let request = indexedDB.open(dbName1, 1);
+ request.onerror = errorHandler;
+ request.onupgradeneeded = unexpectedSuccessHandler;
+ request.onsuccess = grabEventAndContinueHandler;
+ let event = yield undefined;
+
+ is(event.type, "success", "Correct event type");
+
+ request = indexedDB.open(dbName2, 1);
+ request.onerror = errorHandler;
+ request.onupgradeneeded = unexpectedSuccessHandler;
+ request.onsuccess = grabEventAndContinueHandler;
+ event = yield undefined;
+
+ is(event.type, "success", "Got correct event type");
+
+ request = indexedDB.open(dbName3, 1);
+ request.onerror = errorHandler;
+ request.onupgradeneeded = unexpectedSuccessHandler;
+ request.onsuccess = grabEventAndContinueHandler;
+ event = yield undefined;
+
+ is(event.type, "success", "Got correct event type");
+
+ clearAllDatabases(continueToNextStepSync);
+ yield undefined;
+
+ request = indexedDB.open(dbName3, 1);
+ request.onerror = errorHandler;
+ request.onupgradeneeded = grabEventAndContinueHandler;
+ request.onsuccess = unexpectedSuccessHandler;
+ event = yield undefined;
+
+ is(event.type, "upgradeneeded", "Got correct event type");
+
+ request.onupgradeneeded = unexpectedSuccessHandler;
+ request.onsuccess = grabEventAndContinueHandler;
+ event = yield undefined;
+
+ is(event.type, "success", "Got correct event type");
+
+ resetAllDatabases(continueToNextStepSync);
+ yield undefined;
+
+ request = indexedDB.open(dbName3, 1);
+ request.onerror = errorHandler;
+ request.onupgradeneeded = unexpectedSuccessHandler;
+ request.onsuccess = grabEventAndContinueHandler;
+ event = yield undefined;
+
+ is(event.type, "success", "Got correct event type");
+
+ finishTest();
+ yield undefined;
+}
+
+function installPackagedProfile(packageName)
+{
+ let directoryService = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties);
+
+ let profileDir = directoryService.get("ProfD", Ci.nsIFile);
+
+ let currentDir = directoryService.get("CurWorkD", Ci.nsIFile);
+
+ let packageFile = currentDir.clone();
+ packageFile.append(packageName + ".zip");
+
+ let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
+ .createInstance(Ci.nsIZipReader);
+ zipReader.open(packageFile);
+
+ let entryNames = [];
+ let entries = zipReader.findEntries(null);
+ while (entries.hasMore()) {
+ let entry = entries.getNext();
+ if (entry != "create_db.html") {
+ entryNames.push(entry);
+ }
+ }
+ entryNames.sort();
+
+ for (let entryName of entryNames) {
+ let zipentry = zipReader.getEntry(entryName);
+
+ let file = profileDir.clone();
+ let split = entryName.split("/");
+ for(let i = 0; i < split.length; i++) {
+ file.append(split[i]);
+ }
+
+ if (zipentry.isDirectory) {
+ file.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
+ } else {
+ let istream = zipReader.getInputStream(entryName);
+
+ var ostream = Cc["@mozilla.org/network/file-output-stream;1"]
+ .createInstance(Ci.nsIFileOutputStream);
+ ostream.init(file, -1, parseInt("0644", 8), 0);
+
+ let bostream = Cc['@mozilla.org/network/buffered-output-stream;1']
+ .createInstance(Ci.nsIBufferedOutputStream);
+ bostream.init(ostream, 32768);
+
+ bostream.writeFrom(istream, istream.available());
+
+ istream.close();
+ bostream.close();
+ }
+ }
+
+ zipReader.close();
+}
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
+++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
@@ -225,17 +225,17 @@ function setTimeout(fun, timeout) {
fun();
}
};
timer.initWithCallback(event, timeout,
Components.interfaces.nsITimer.TYPE_ONE_SHOT);
return timer;
}
-function clearAllDatabases(callback) {
+function resetOrClearAllDatabases(callback, clear) {
if (!SpecialPowers.isMainProcess()) {
throw new Error("clearAllDatabases not implemented for child processes!");
}
let quotaManager = Cc["@mozilla.org/dom/quota/manager;1"]
.getService(Ci.nsIQuotaManager);
const quotaPref = "dom.quotaManager.testing";
@@ -243,17 +243,21 @@ function clearAllDatabases(callback) {
let oldPrefValue;
if (SpecialPowers._getPrefs().prefHasUserValue(quotaPref)) {
oldPrefValue = SpecialPowers.getBoolPref(quotaPref);
}
SpecialPowers.setBoolPref(quotaPref, true);
try {
- quotaManager.clear();
+ if (clear) {
+ quotaManager.clear();
+ } else {
+ quotaManager.reset();
+ }
} catch(e) {
if (oldPrefValue !== undefined) {
SpecialPowers.setBoolPref(quotaPref, oldPrefValue);
} else {
SpecialPowers.clearUserPref(quotaPref);
}
throw e;
}
@@ -261,16 +265,24 @@ function clearAllDatabases(callback) {
let uri = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI("http://foo.com", null, null);
quotaManager.getUsageForURI(uri, function(usage, fileUsage) {
callback();
});
}
+function resetAllDatabases(callback) {
+ resetOrClearAllDatabases(callback, false);
+}
+
+function clearAllDatabases(callback) {
+ resetOrClearAllDatabases(callback, true);
+}
+
var SpecialPowers = {
isMainProcess: function() {
return Components.classes["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULRuntime)
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
},
notifyObservers: function(subject, topic, data) {
var obsvc = Cc['@mozilla.org/observer-service;1']
--- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
@@ -3,25 +3,27 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[DEFAULT]
dupe-manifest =
head = xpcshell-head-parent-process.js
tail =
skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
+ bug1056939.zip
GlobalObjectsChild.js
GlobalObjectsComponent.js
GlobalObjectsComponent.manifest
GlobalObjectsModule.jsm
GlobalObjectsSandbox.js
xpcshell-shared.ini
[include:xpcshell-shared.ini]
+[test_bug1056939.js]
[test_globalObjects_ipc.js]
[test_invalidate.js]
# disabled for the moment.
skip-if = true
[test_lowDiskSpace.js]
[test_temporary_storage.js]
# bug 951017: intermittent failure on Android x86 emulator
skip-if = os == "android" && processor == "x86"
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -1092,16 +1092,36 @@ public:
NoteDyingActor()
{
MOZ_ASSERT(mActor);
mActor->AssertIsOnOwningThread();
mActor = nullptr;
}
+ BlobChild*
+ GetActor() const
+ {
+ AssertActorEventTargetIsOnCurrentThread();
+
+ return mActor;
+ }
+
+ nsIEventTarget*
+ GetActorEventTarget() const
+ {
+ return mActorTarget;
+ }
+
+ void
+ AssertActorEventTargetIsOnCurrentThread() const
+ {
+ MOZ_ASSERT(EventTargetIsOnCurrentThread(mActorTarget));
+ }
+
NS_DECL_ISUPPORTS_INHERITED
virtual void
GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) MOZ_OVERRIDE;
virtual already_AddRefed<FileImpl>
CreateSlice(uint64_t aStart, uint64_t aLength,
const nsAString& aContentType, ErrorResult& aRv) MOZ_OVERRIDE;
@@ -1163,46 +1183,43 @@ private:
}
}
};
class BlobChild::RemoteBlobImpl::StreamHelper MOZ_FINAL
: public nsRunnable
{
Monitor mMonitor;
- BlobChild* mActor;
- nsRefPtr<FileImpl> mBlobImpl;
+ nsRefPtr<RemoteBlobImpl> mRemoteBlobImpl;
nsRefPtr<RemoteInputStream> mInputStream;
bool mDone;
public:
- StreamHelper(BlobChild* aActor, FileImpl* aBlobImpl)
+ StreamHelper(RemoteBlobImpl* aRemoteBlobImpl)
: mMonitor("BlobChild::RemoteBlobImpl::StreamHelper::mMonitor")
- , mActor(aActor)
- , mBlobImpl(aBlobImpl)
+ , mRemoteBlobImpl(aRemoteBlobImpl)
, mDone(false)
{
// This may be created on any thread.
- MOZ_ASSERT(aActor);
- MOZ_ASSERT(aBlobImpl);
+ MOZ_ASSERT(aRemoteBlobImpl);
}
nsresult
GetStream(nsIInputStream** aInputStream)
{
// This may be called on any thread.
MOZ_ASSERT(aInputStream);
- MOZ_ASSERT(mActor);
+ MOZ_ASSERT(mRemoteBlobImpl);
MOZ_ASSERT(!mInputStream);
MOZ_ASSERT(!mDone);
- if (mActor->IsOnOwningThread()) {
+ if (EventTargetIsOnCurrentThread(mRemoteBlobImpl->GetActorEventTarget())) {
RunInternal(false);
} else {
- nsCOMPtr<nsIEventTarget> target = mActor->EventTarget();
+ nsCOMPtr<nsIEventTarget> target = mRemoteBlobImpl->GetActorEventTarget();
if (!target) {
target = do_GetMainThread();
}
MOZ_ASSERT(target);
nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
@@ -1210,108 +1227,109 @@ public:
{
MonitorAutoLock lock(mMonitor);
while (!mDone) {
lock.Wait();
}
}
}
- MOZ_ASSERT(!mActor);
+ MOZ_ASSERT(!mRemoteBlobImpl);
MOZ_ASSERT(mDone);
if (!mInputStream) {
return NS_ERROR_UNEXPECTED;
}
mInputStream.forget(aInputStream);
return NS_OK;
}
NS_IMETHOD
Run() MOZ_OVERRIDE
{
- MOZ_ASSERT(mActor);
- mActor->AssertIsOnOwningThread();
+ MOZ_ASSERT(mRemoteBlobImpl);
+ mRemoteBlobImpl->AssertActorEventTargetIsOnCurrentThread();
RunInternal(true);
return NS_OK;
}
private:
void
RunInternal(bool aNotify)
{
- MOZ_ASSERT(mActor);
- mActor->AssertIsOnOwningThread();
+ MOZ_ASSERT(mRemoteBlobImpl);
+ mRemoteBlobImpl->AssertActorEventTargetIsOnCurrentThread();
MOZ_ASSERT(!mInputStream);
MOZ_ASSERT(!mDone);
- nsRefPtr<RemoteInputStream> stream = new RemoteInputStream(mBlobImpl);
-
- InputStreamChild* streamActor = new InputStreamChild(stream);
- if (mActor->SendPBlobStreamConstructor(streamActor)) {
- stream.swap(mInputStream);
+ if (BlobChild* actor = mRemoteBlobImpl->GetActor()) {
+ nsRefPtr<RemoteInputStream> stream =
+ new RemoteInputStream(mRemoteBlobImpl);
+
+ InputStreamChild* streamActor = new InputStreamChild(stream);
+ if (actor->SendPBlobStreamConstructor(streamActor)) {
+ stream.swap(mInputStream);
+ }
}
- mActor = nullptr;
+ mRemoteBlobImpl = nullptr;
if (aNotify) {
MonitorAutoLock lock(mMonitor);
mDone = true;
lock.Notify();
}
else {
mDone = true;
}
}
};
class BlobChild::RemoteBlobImpl::SliceHelper MOZ_FINAL
: public nsRunnable
{
Monitor mMonitor;
- BlobChild* mActor;
+ nsRefPtr<RemoteBlobImpl> mRemoteBlobImpl;
nsRefPtr<FileImpl> mSlice;
uint64_t mStart;
uint64_t mLength;
nsString mContentType;
bool mDone;
public:
explicit
- SliceHelper(BlobChild* aActor)
+ SliceHelper(RemoteBlobImpl* aRemoteBlobImpl)
: mMonitor("BlobChild::RemoteBlobImpl::SliceHelper::mMonitor")
- , mActor(aActor)
+ , mRemoteBlobImpl(aRemoteBlobImpl)
, mStart(0)
, mLength(0)
, mDone(false)
{
// This may be created on any thread.
- MOZ_ASSERT(aActor);
+ MOZ_ASSERT(aRemoteBlobImpl);
}
- FileImpl*
- GetSlice(uint64_t aStart,
- uint64_t aLength,
- const nsAString& aContentType)
+ already_AddRefed<FileImpl>
+ GetSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
{
// This may be called on any thread.
- MOZ_ASSERT(mActor);
+ MOZ_ASSERT(mRemoteBlobImpl);
MOZ_ASSERT(!mSlice);
MOZ_ASSERT(!mDone);
mStart = aStart;
mLength = aLength;
mContentType = aContentType;
- if (mActor->IsOnOwningThread()) {
+ if (EventTargetIsOnCurrentThread(mRemoteBlobImpl->GetActorEventTarget())) {
RunInternal(false);
} else {
- nsCOMPtr<nsIEventTarget> target = mActor->EventTarget();
+ nsCOMPtr<nsIEventTarget> target = mRemoteBlobImpl->GetActorEventTarget();
if (!target) {
target = do_GetMainThread();
}
MOZ_ASSERT(target);
nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1321,78 +1339,82 @@ public:
{
MonitorAutoLock lock(mMonitor);
while (!mDone) {
lock.Wait();
}
}
}
- MOZ_ASSERT(!mActor);
+ MOZ_ASSERT(!mRemoteBlobImpl);
MOZ_ASSERT(mDone);
if (NS_WARN_IF(!mSlice)) {
return nullptr;
}
- return mSlice;
+ return mSlice.forget();
}
NS_IMETHOD
Run() MOZ_OVERRIDE
{
- MOZ_ASSERT(mActor);
- mActor->AssertIsOnOwningThread();
+ MOZ_ASSERT(mRemoteBlobImpl);
+ mRemoteBlobImpl->AssertActorEventTargetIsOnCurrentThread();
RunInternal(true);
return NS_OK;
}
private:
void
RunInternal(bool aNotify)
{
- MOZ_ASSERT(mActor);
- mActor->AssertIsOnOwningThread();
+ MOZ_ASSERT(mRemoteBlobImpl);
+ mRemoteBlobImpl->AssertActorEventTargetIsOnCurrentThread();
MOZ_ASSERT(!mSlice);
MOZ_ASSERT(!mDone);
- NS_ENSURE_TRUE_VOID(mActor->HasManager());
-
- nsID id;
- MOZ_ALWAYS_TRUE(NS_SUCCEEDED(gUUIDGenerator->GenerateUUIDInPlace(&id)));
-
- ChildBlobConstructorParams params(
- id,
- NormalBlobConstructorParams(mContentType /* contentType */,
- mLength /* length */));
-
- ParentBlobConstructorParams otherSideParams(
- SlicedBlobConstructorParams(nullptr /* sourceParent */,
- mActor /* sourceChild */,
- id /* optionalID */,
- mStart /* begin */,
- mStart + mLength /* end */,
- mContentType /* contentType */),
- void_t() /* optionalInputStream */);
-
- BlobChild* newActor;
- if (nsIContentChild* contentManager = mActor->GetContentManager()) {
- newActor = SendSliceConstructor(contentManager, params, otherSideParams);
- } else {
- newActor = SendSliceConstructor(mActor->GetBackgroundManager(),
- params,
- otherSideParams);
+ if (BlobChild* actor = mRemoteBlobImpl->GetActor()) {
+ MOZ_ASSERT(actor->HasManager());
+
+ nsID id;
+ MOZ_ALWAYS_TRUE(NS_SUCCEEDED(gUUIDGenerator->GenerateUUIDInPlace(&id)));
+
+ ChildBlobConstructorParams params(
+ id,
+ NormalBlobConstructorParams(mContentType /* contentType */,
+ mLength /* length */));
+
+ ParentBlobConstructorParams otherSideParams(
+ SlicedBlobConstructorParams(nullptr /* sourceParent */,
+ actor /* sourceChild */,
+ id /* optionalID */,
+ mStart /* begin */,
+ mStart + mLength /* end */,
+ mContentType /* contentType */),
+ void_t() /* optionalInputStream */);
+
+ BlobChild* newActor;
+ if (nsIContentChild* contentManager = actor->GetContentManager()) {
+ newActor = SendSliceConstructor(contentManager,
+ params,
+ otherSideParams);
+ } else {
+ newActor = SendSliceConstructor(actor->GetBackgroundManager(),
+ params,
+ otherSideParams);
+ }
+
+ if (newActor) {
+ mSlice = newActor->GetBlobImpl();
+ }
}
- if (newActor) {
- mSlice = newActor->GetBlobImpl();
- }
-
- mActor = nullptr;
+ mRemoteBlobImpl = nullptr;
if (aNotify) {
MonitorAutoLock lock(mMonitor);
mDone = true;
lock.Notify();
}
else {
mDone = true;
@@ -1410,16 +1432,20 @@ NS_IMPL_QUERY_INTERFACE_INHERITED(BlobCh
FileImpl,
nsIRemoteBlob)
void
BlobChild::
RemoteBlobImpl::GetMozFullPathInternal(nsAString& aFilePath,
ErrorResult& aRv)
{
+ if (!EventTargetIsOnCurrentThread(mActorTarget)) {
+ MOZ_CRASH("Not implemented!");
+ }
+
if (!mActor) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return;
}
nsString filePath;
if (!mActor->SendGetFilePath(&filePath)) {
aRv.Throw(NS_ERROR_FAILURE);
@@ -1429,48 +1455,43 @@ RemoteBlobImpl::GetMozFullPathInternal(n
aFilePath = filePath;
}
already_AddRefed<FileImpl>
BlobChild::
RemoteBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
const nsAString& aContentType, ErrorResult& aRv)
{
- if (!mActor) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
-
- nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
+ nsRefPtr<SliceHelper> helper = new SliceHelper(this);
nsRefPtr<FileImpl> impl = helper->GetSlice(aStart, aLength, aContentType);
if (NS_WARN_IF(!impl)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
return impl.forget();
}
nsresult
BlobChild::
RemoteBlobImpl::GetInternalStream(nsIInputStream** aStream)
{
- if (!mActor) {
- return NS_ERROR_UNEXPECTED;
- }
-
- nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
+ nsRefPtr<StreamHelper> helper = new StreamHelper(this);
return helper->GetStream(aStream);
}
int64_t
BlobChild::
RemoteBlobImpl::GetFileId()
{
+ if (!EventTargetIsOnCurrentThread(mActorTarget)) {
+ MOZ_CRASH("Not implemented!");
+ }
+
int64_t fileId;
if (mActor && mActor->SendGetFileId(&fileId)) {
return fileId;
}
return -1;
}
--- a/dom/ipc/ContentProcess.h
+++ b/dom/ipc/ContentProcess.h
@@ -6,19 +6,16 @@
#ifndef dom_tabs_ContentThread_h
#define dom_tabs_ContentThread_h 1
#include "mozilla/ipc/ProcessChild.h"
#include "mozilla/ipc/ScopedXREEmbed.h"
#include "ContentChild.h"
-#undef _MOZ_LOG
-#define _MOZ_LOG(s) printf("[ContentProcess] %s", s)
-
namespace mozilla {
namespace dom {
/**
* ContentProcess is a singleton on the content process which represents
* the main thread where tab instances live.
*/
class ContentProcess : public mozilla::ipc::ProcessChild
--- a/dom/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -377,18 +377,17 @@ public:
}
}
static void
InvalidateOpenedStorages(nsTArray<nsCOMPtr<nsIOfflineStorage> >& aStorages,
void* aClosure);
void
- DeleteFiles(QuotaManager* aQuotaManager,
- PersistenceType aPersistenceType);
+ DeleteFiles(QuotaManager* aQuotaManager);
private:
~ResetOrClearRunnable() {}
CallbackState mCallbackState;
bool mClear;
};
@@ -988,16 +987,19 @@ QuotaManager::Init()
NS_ENSURE_SUCCESS(rv, rv);
rv = indexedDBDir->GetPath(mIndexedDBPath);
NS_ENSURE_SUCCESS(rv, rv);
rv = baseDir->Append(NS_LITERAL_STRING("storage"));
NS_ENSURE_SUCCESS(rv, rv);
+ rv = baseDir->GetPath(mStoragePath);
+ NS_ENSURE_SUCCESS(rv, rv);
+
nsCOMPtr<nsIFile> persistentStorageDir;
rv = baseDir->Clone(getter_AddRefs(persistentStorageDir));
NS_ENSURE_SUCCESS(rv, rv);
rv = persistentStorageDir->Append(NS_LITERAL_STRING("persistent"));
NS_ENSURE_SUCCESS(rv, rv);
rv = persistentStorageDir->GetPath(mPersistentStoragePath);
@@ -1972,16 +1974,17 @@ QuotaManager::OriginClearCompleted(
void
QuotaManager::ResetOrClearCompleted()
{
AssertIsOnIOThread();
mInitializedOrigins.Clear();
mTemporaryStorageInitialized = false;
+ mStorageAreaInitialized = false;
ReleaseIOThreadObjects();
}
already_AddRefed<mozilla::dom::quota::Client>
QuotaManager::GetClient(Client::Type aClientType)
{
nsRefPtr<Client> client = mClients.SafeElementAt(aClientType);
@@ -3923,29 +3926,28 @@ ResetOrClearRunnable::InvalidateOpenedSt
storages.SwapElements(aStorages);
for (uint32_t index = 0; index < storages.Length(); index++) {
storages[index]->Invalidate();
}
}
void
-ResetOrClearRunnable::DeleteFiles(QuotaManager* aQuotaManager,
- PersistenceType aPersistenceType)
+ResetOrClearRunnable::DeleteFiles(QuotaManager* aQuotaManager)
{
AssertIsOnIOThread();
NS_ASSERTION(aQuotaManager, "Don't pass me null!");
nsresult rv;
nsCOMPtr<nsIFile> directory =
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS_VOID(rv);
- rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType));
+ rv = directory->InitWithPath(aQuotaManager->GetStoragePath());
NS_ENSURE_SUCCESS_VOID(rv);
rv = directory->Remove(true);
if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST &&
rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
// This should never fail if we've closed all storage connections
// correctly...
NS_ERROR("Failed to remove directory!");
@@ -3983,18 +3985,17 @@ ResetOrClearRunnable::Run()
}
case IO: {
AssertIsOnIOThread();
AdvanceState();
if (mClear) {
- DeleteFiles(quotaManager, PERSISTENCE_TYPE_PERSISTENT);
- DeleteFiles(quotaManager, PERSISTENCE_TYPE_TEMPORARY);
+ DeleteFiles(quotaManager);
}
quotaManager->RemoveQuota();
quotaManager->ResetOrClearCompleted();
// Now dispatch back to the main thread.
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
NS_WARNING("Failed to dispatch to main thread!");
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -275,16 +275,22 @@ public:
NS_ASSERTION(mIOThread, "This should never be null!");
return mIOThread;
}
already_AddRefed<Client>
GetClient(Client::Type aClientType);
const nsString&
+ GetStoragePath() const
+ {
+ return mStoragePath;
+ }
+
+ const nsString&
GetStoragePath(PersistenceType aPersistenceType) const
{
if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
return mPersistentStoragePath;
}
NS_ASSERTION(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY, "Huh?");
@@ -515,16 +521,17 @@ private:
// A list of all successfully initialized origins. This list isn't protected
// by any mutex but it is only ever touched on the IO thread.
nsTArray<nsCString> mInitializedOrigins;
nsAutoTArray<nsRefPtr<Client>, Client::TYPE_MAX> mClients;
nsString mIndexedDBPath;
+ nsString mStoragePath;
nsString mPersistentStoragePath;
nsString mTemporaryStoragePath;
uint64_t mTemporaryStorageLimit;
uint64_t mTemporaryStorageUsage;
bool mTemporaryStorageInitialized;
bool mStorageAreaInitialized;
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -45,19 +45,21 @@ CompositorChild::~CompositorChild()
MOZ_COUNT_DTOR(CompositorChild);
}
void
CompositorChild::Destroy()
{
mLayerManager->Destroy();
mLayerManager = nullptr;
- while (size_t len = ManagedPLayerTransactionChild().Length()) {
+ // start from the end of the array because Destroy() can cause the
+ // LayerTransactionChild to be removed from the array.
+ for (int i = ManagedPLayerTransactionChild().Length() - 1; i >= 0; --i) {
RefPtr<LayerTransactionChild> layers =
- static_cast<LayerTransactionChild*>(ManagedPLayerTransactionChild()[len - 1]);
+ static_cast<LayerTransactionChild*>(ManagedPLayerTransactionChild()[i]);
layers->Destroy();
}
SendStop();
}
bool
CompositorChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId,
FrameMetrics& aFrame)
--- a/gfx/layers/ipc/LayerTransactionChild.cpp
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -17,29 +17,37 @@
namespace mozilla {
namespace layers {
void
LayerTransactionChild::Destroy()
{
- if (!IPCOpen() || mDestroyed) {
+ if (!IPCOpen()) {
return;
}
// mDestroyed is used to prevent calling Send__delete__() twice.
// When this function is called from CompositorChild::Destroy(),
// under Send__delete__() call, this function is called from
// ShadowLayerForwarder's destructor.
// When it happens, IPCOpen() is still true.
// See bug 1004191.
mDestroyed = true;
NS_ABORT_IF_FALSE(0 == ManagedPLayerChild().Length(),
"layers should have been cleaned up by now");
- PLayerTransactionChild::Send__delete__(this);
+
+ for (size_t i = 0; i < ManagedPTextureChild().Length(); ++i) {
+ TextureClient* texture = TextureClient::AsTextureClient(ManagedPTextureChild()[i]);
+ if (texture) {
+ texture->ForceRemove();
+ }
+ }
+
+ SendShutdown();
}
PLayerChild*
LayerTransactionChild::AllocPLayerChild()
{
// we always use the "power-user" ctor
NS_RUNTIMEABORT("not reached");
@@ -51,16 +59,17 @@ LayerTransactionChild::DeallocPLayerChil
{
delete actor;
return true;
}
PCompositableChild*
LayerTransactionChild::AllocPCompositableChild(const TextureInfo& aInfo)
{
+ MOZ_ASSERT(!mDestroyed);
return CompositableClient::CreateIPDLActor();
}
bool
LayerTransactionChild::DeallocPCompositableChild(PCompositableChild* actor)
{
return CompositableClient::DestroyIPDLActor(actor);
}
@@ -131,16 +140,17 @@ LayerTransactionChild::ActorDestroy(Acto
}
#endif
}
PTextureChild*
LayerTransactionChild::AllocPTextureChild(const SurfaceDescriptor&,
const TextureFlags&)
{
+ MOZ_ASSERT(!mDestroyed);
return TextureClient::CreateIPDLActor();
}
bool
LayerTransactionChild::DeallocPTextureChild(PTextureChild* actor)
{
return TextureClient::DestroyIPDLActor(actor);
}
--- a/gfx/layers/ipc/LayerTransactionChild.h
+++ b/gfx/layers/ipc/LayerTransactionChild.h
@@ -26,25 +26,26 @@ namespace layers {
class LayerTransactionChild : public PLayerTransactionChild
, public AsyncTransactionTrackersHolder
{
typedef InfallibleTArray<AsyncParentMessageData> AsyncParentMessageArray;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LayerTransactionChild)
/**
- * Clean this up, finishing with Send__delete__().
+ * Clean this up, finishing with SendShutDown() which will cause __delete__
+ * to be sent from the parent side.
*
* It is expected (checked with an assert) that all shadow layers
* created by this have already been destroyed and
* Send__delete__()d by the time this method is called.
*/
void Destroy();
- bool IPCOpen() const { return mIPCOpen; }
+ bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
void SetForwarder(ShadowLayerForwarder* aForwarder)
{
mForwarder = aForwarder;
}
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureChild* aTexture,
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -156,16 +156,23 @@ LayerTransactionParent::LayerTransaction
MOZ_COUNT_CTOR(LayerTransactionParent);
}
LayerTransactionParent::~LayerTransactionParent()
{
MOZ_COUNT_DTOR(LayerTransactionParent);
}
+bool
+LayerTransactionParent::RecvShutdown()
+{
+ Destroy();
+ return Send__delete__(this);
+}
+
void
LayerTransactionParent::Destroy()
{
mDestroyed = true;
for (size_t i = 0; i < ManagedPLayerParent().Length(); ++i) {
ShadowLayerParent* slp =
static_cast<ShadowLayerParent*>(ManagedPLayerParent()[i]);
slp->Destroy();
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -96,16 +96,18 @@ public:
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) MOZ_OVERRIDE;
virtual base::ProcessId GetChildProcessId() MOZ_OVERRIDE
{
return mChildProcessId;
}
protected:
+ virtual bool RecvShutdown() MOZ_OVERRIDE;
+
virtual bool RecvUpdate(const EditArray& cset,
const uint64_t& aTransactionId,
const TargetConfig& targetConfig,
const bool& isFirstPaint,
const bool& scheduleComposite,
const uint32_t& paintSequenceNumber,
const bool& isRepeatTransaction,
const mozilla::TimeStamp& aTransactionStart,
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -97,13 +97,15 @@ parent:
// layers id.
sync GetAPZTestData() returns (APZTestData data);
// Query a named property from the last frame
sync RequestProperty(nsString property) returns (float value);
async ChildAsyncMessages(AsyncChildMessageData[] aMessages);
+ async Shutdown();
+child:
async __delete__();
};
} // namespace layers
} // namespace mozilla
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -1645,17 +1645,17 @@ IsNativeRegExpEnabled(JSContext *cx)
#else
return cx->runtime()->options().nativeRegExp();
#endif
}
RegExpCode
irregexp::CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
HandleLinearString sample, bool is_global, bool ignore_case,
- bool is_ascii, bool match_only)
+ bool is_ascii, bool match_only, bool force_bytecode)
{
if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) {
JS_ReportError(cx, "regexp too big");
return RegExpCode();
}
LifoAlloc &alloc = cx->tempLifoAlloc();
RegExpCompiler compiler(cx, &alloc, data->capture_count, ignore_case, is_ascii, match_only);
@@ -1722,17 +1722,17 @@ irregexp::CompilePattern(JSContext *cx,
return RegExpCode();
}
Maybe<jit::IonContext> ctx;
Maybe<NativeRegExpMacroAssembler> native_assembler;
Maybe<InterpretedRegExpMacroAssembler> interpreted_assembler;
RegExpMacroAssembler *assembler;
- if (IsNativeRegExpEnabled(cx)) {
+ if (IsNativeRegExpEnabled(cx) && !force_bytecode) {
NativeRegExpMacroAssembler::Mode mode =
is_ascii ? NativeRegExpMacroAssembler::ASCII
: NativeRegExpMacroAssembler::CHAR16;
ctx.emplace(cx, (jit::TempAllocator *) nullptr);
native_assembler.emplace(&alloc, shared, cx->runtime(), mode, (data->capture_count + 1) * 2);
assembler = native_assembler.ptr();
} else {
--- a/js/src/irregexp/RegExpEngine.h
+++ b/js/src/irregexp/RegExpEngine.h
@@ -83,17 +83,17 @@ struct RegExpCode
void destroy() {
js_free(byteCode);
}
};
RegExpCode
CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
HandleLinearString sample, bool is_global, bool ignore_case,
- bool is_ascii, bool match_only);
+ bool is_ascii, bool match_only, bool force_bytecode);
// Note: this may return RegExpRunStatus_Error if an interrupt was requested
// while the code was executing.
template <typename CharT>
RegExpRunStatus
ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const CharT *chars, size_t start,
size_t length, MatchPairs *matches);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug999655.js
@@ -0,0 +1,11 @@
+
+var g = newGlobal();
+var dbg = new Debugger(g);
+dbg.onNewScript = function(script) {
+ fscript = script.getChildScripts()[0];
+}
+g.eval("function f(x) { arguments[0] = 3; return x }");
+fscript.setBreakpoint(0, {hit:function(frame) {
+ assertEq(frame.arguments[0], 1);
+}});
+g.f(1);
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -19,89 +19,42 @@
#include "vm/Probes-inl.h"
#include "vm/Stack-inl.h"
using namespace js;
using namespace js::jit;
using mozilla::IsInRange;
-// These constructor are exactly the same except for the type of the iterator
-// which is given to the SnapshotIterator constructor. Doing so avoid the
-// creation of virtual functions for the IonIterator but may introduce some
-// weirdness as IonInlineIterator is using a JitFrameIterator reference.
-//
-// If a function relies on ionScript() or to use OsiIndex(), due to the
-// lack of virtual, these functions will use the JitFrameIterator reference
-// contained in the InlineFrameIterator and thus are not able to recover
-// correctly the data stored in IonBailoutIterator.
-//
-// Currently, such cases should not happen because our only use case of the
-// JitFrameIterator within InlineFrameIterator is to read the frame content, or
-// to clone it to find the parent scripted frame. Both use cases are fine and
-// should not cause any issue since the only potential issue is to read the
-// bailed out frame.
-
-SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter)
- : snapshot_(iter.ionScript()->snapshots(),
- iter.snapshotOffset(),
- iter.ionScript()->snapshotsRVATableSize(),
- iter.ionScript()->snapshotsListSize()),
- recover_(snapshot_,
- iter.ionScript()->recovers(),
- iter.ionScript()->recoversSize()),
- fp_(iter.jsFrame()),
- machine_(iter.machineState()),
- ionScript_(iter.ionScript()),
- instructionResults_(nullptr)
-{
-}
-
-void
-IonBailoutIterator::dump() const
-{
- if (type_ == JitFrame_IonJS) {
- InlineFrameIterator frames(GetJSContextFromJitCode(), this);
- for (;;) {
- frames.dump();
- if (!frames.more())
- break;
- ++frames;
- }
- } else {
- JitFrameIterator::dump();
- }
-}
-
uint32_t
jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
{
JSContext *cx = GetJSContextFromJitCode();
MOZ_ASSERT(bailoutInfo);
// We don't have an exit frame.
MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
"Fake jitTop pointer should be within the first page.");
cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
gc::AutoSuppressGC suppress(cx);
JitActivationIterator jitActivations(cx->runtime());
- IonBailoutIterator iter(jitActivations, sp);
- JitActivation *activation = jitActivations->asJit();
+ BailoutFrameInfo bailoutData(jitActivations, sp);
+ JitFrameIterator iter(jitActivations);
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
TraceLogTimestamp(logger, TraceLogger::Bailout);
JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
MOZ_ASSERT(IsBaselineEnabled(cx));
*bailoutInfo = nullptr;
- uint32_t retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo);
+ uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo);
MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
retval == BAILOUT_RETURN_FATAL_ERROR ||
retval == BAILOUT_RETURN_OVERRECURSED);
MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
if (retval != BAILOUT_RETURN_OK) {
// If the bailout failed, then bailout trampoline will pop the
// current frame and jump straight to exception handling code when
@@ -133,31 +86,31 @@ jit::InvalidationBailout(InvalidationBai
JSContext *cx = GetJSContextFromJitCode();
// We don't have an exit frame.
cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
gc::AutoSuppressGC suppress(cx);
JitActivationIterator jitActivations(cx->runtime());
- IonBailoutIterator iter(jitActivations, sp);
- JitActivation *activation = jitActivations->asJit();
+ BailoutFrameInfo bailoutData(jitActivations, sp);
+ JitFrameIterator iter(jitActivations);
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
TraceLogTimestamp(logger, TraceLogger::Invalidation);
JitSpew(JitSpew_IonBailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
// Note: the frame size must be computed before we return from this function.
- *frameSizeOut = iter.topFrameSize();
+ *frameSizeOut = iter.frameSize();
MOZ_ASSERT(IsBaselineEnabled(cx));
*bailoutInfo = nullptr;
- uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo);
+ uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo);
MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
retval == BAILOUT_RETURN_FATAL_ERROR ||
retval == BAILOUT_RETURN_OVERRECURSED);
MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
if (retval != BAILOUT_RETURN_OK) {
// If the bailout failed, then bailout trampoline will pop the
// current frame and jump straight to exception handling code when
@@ -190,29 +143,26 @@ jit::InvalidationBailout(InvalidationBai
JitSpew(JitSpew_IonInvalidate, " new ra %p", (void *) frame->returnAddress());
}
iter.ionScript()->decref(cx->runtime()->defaultFreeOp());
return retval;
}
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
- const JitFrameIterator &frame)
- : JitFrameIterator(activations),
- machine_(frame.machineState())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+ const JitFrameIterator &frame)
+ : machine_(frame.machineState())
{
- kind_ = Kind_BailoutIterator;
- returnAddressToFp_ = frame.returnAddressToFp();
+ framePointer_ = (uint8_t *) frame.fp();
+ topFrameSize_ = frame.frameSize();
topIonScript_ = frame.ionScript();
+ attachOnJitActivation(activations);
+
const OsiIndex *osiIndex = frame.osiIndex();
-
- current_ = (uint8_t *) frame.fp();
- type_ = JitFrame_IonJS;
- topFrameSize_ = frame.frameSize();
snapshotOffset_ = osiIndex->snapshotOffset();
}
uint32_t
jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
ResumeFromException *rfe,
const ExceptionBailoutInfo &excInfo,
bool *overrecursed)
@@ -221,21 +171,21 @@ jit::ExceptionHandlerBailout(JSContext *
// actual exception pending. For instance, when we return false from an
// operation callback like a timeout handler.
MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending());
cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
gc::AutoSuppressGC suppress(cx);
JitActivationIterator jitActivations(cx->runtime());
- IonBailoutIterator iter(jitActivations, frame.frame());
- JitActivation *activation = jitActivations->asJit();
+ BailoutFrameInfo bailoutData(jitActivations, frame.frame());
+ JitFrameIterator iter(jitActivations);
BaselineBailoutInfo *bailoutInfo = nullptr;
- uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, &bailoutInfo, &excInfo);
+ uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, &bailoutInfo, &excInfo);
if (retval == BAILOUT_RETURN_OK) {
MOZ_ASSERT(bailoutInfo);
// Overwrite the kind so HandleException after the bailout returns
// false, jumping directly to the exception tail.
if (excInfo.propagatingIonExceptionForDebugMode())
bailoutInfo->bailoutKind = Bailout_IonExceptionDebugMode;
@@ -292,8 +242,21 @@ jit::CheckFrequentBailouts(JSContext *cx
if (!Invalidate(cx, script))
return false;
}
}
return true;
}
+
+void
+BailoutFrameInfo::attachOnJitActivation(const JitActivationIterator &jitActivations)
+{
+ MOZ_ASSERT(jitActivations.jitTop() == FAKE_JIT_TOP_FOR_BAILOUT);
+ activation_ = jitActivations->asJit();
+ activation_->setBailoutData(this);
+}
+
+BailoutFrameInfo::~BailoutFrameInfo()
+{
+ activation_->cleanBailoutData();
+}
--- a/js/src/jit/Bailouts.h
+++ b/js/src/jit/Bailouts.h
@@ -108,60 +108,54 @@ class JitCompartment;
// BailoutStack is an architecture specific pointer to the stack, given by the
// bailout handler.
class BailoutStack;
class InvalidationBailoutStack;
// Must be implemented by each architecture.
-// This iterator is constructed at a time where there is no exit frame at the
-// moment. They must be initialized to the first JS frame instead of the exit
-// frame as usually done with JitFrameIterator.
-class IonBailoutIterator : public JitFrameIterator
+// This structure is constructed before recovering the baseline frames for a
+// bailout. It records all information extracted from the stack, and which are
+// needed for the JitFrameIterator.
+class BailoutFrameInfo
{
MachineState machine_;
- uint32_t snapshotOffset_;
+ uint8_t *framePointer_;
size_t topFrameSize_;
IonScript *topIonScript_;
+ uint32_t snapshotOffset_;
+ JitActivation *activation_;
+
+ void attachOnJitActivation(const JitActivationIterator &activations);
public:
- IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *sp);
- IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *sp);
- IonBailoutIterator(const JitActivationIterator &activations, const JitFrameIterator &frame);
+ BailoutFrameInfo(const JitActivationIterator &activations, BailoutStack *sp);
+ BailoutFrameInfo(const JitActivationIterator &activations, InvalidationBailoutStack *sp);
+ BailoutFrameInfo(const JitActivationIterator &activations, const JitFrameIterator &frame);
+ ~BailoutFrameInfo();
+ uint8_t *fp() const {
+ return framePointer_;
+ }
SnapshotOffset snapshotOffset() const {
- if (topIonScript_)
- return snapshotOffset_;
- return osiIndex()->snapshotOffset();
+ return snapshotOffset_;
}
const MachineState machineState() const {
- if (topIonScript_)
- return machine_;
- return JitFrameIterator::machineState();
+ return machine_;
}
size_t topFrameSize() const {
- MOZ_ASSERT(topIonScript_);
return topFrameSize_;
}
IonScript *ionScript() const {
- if (topIonScript_)
- return topIonScript_;
- return JitFrameIterator::ionScript();
+ return topIonScript_;
}
-
- IonBailoutIterator &operator++() {
- JitFrameIterator::operator++();
- // Clear topIonScript_ now that we've advanced past it, so that
- // snapshotOffset() and machineState() reflect the current script.
- topIonScript_ = nullptr;
- return *this;
+ JitActivation *activation() const {
+ return activation_;
}
-
- void dump() const;
};
bool EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp);
struct BaselineBailoutInfo;
// Called from a bailout thunk. Returns a BAILOUT_* error code.
uint32_t Bailout(BailoutStack *sp, BaselineBailoutInfo **info);
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -69,41 +69,42 @@ class BufferPointer
* needs to be enlarged to accomodate new data. Similarly to the C stack, the
* data that's written to the reconstructed stack grows from high to low in memory.
*
* The lowest region of the allocated memory contains a BaselineBailoutInfo structure that
* points to the start and end of the written data.
*/
struct BaselineStackBuilder
{
- IonBailoutIterator &iter_;
+ JitFrameIterator &iter_;
IonJSFrameLayout *frame_;
static size_t HeaderSize() {
return AlignBytes(sizeof(BaselineBailoutInfo), sizeof(void *));
}
size_t bufferTotal_;
size_t bufferAvail_;
size_t bufferUsed_;
uint8_t *buffer_;
BaselineBailoutInfo *header_;
size_t framePushed_;
- BaselineStackBuilder(IonBailoutIterator &iter, size_t initialSize)
+ BaselineStackBuilder(JitFrameIterator &iter, size_t initialSize)
: iter_(iter),
frame_(static_cast<IonJSFrameLayout*>(iter.current())),
bufferTotal_(initialSize),
bufferAvail_(0),
bufferUsed_(0),
buffer_(nullptr),
header_(nullptr),
framePushed_(0)
{
MOZ_ASSERT(bufferTotal_ >= HeaderSize());
+ MOZ_ASSERT(iter.isBailoutJS());
}
~BaselineStackBuilder() {
js_free(buffer_);
}
bool init() {
MOZ_ASSERT(!buffer_);
@@ -382,20 +383,21 @@ struct BaselineStackBuilder
// Ensure that all value locations are readable from the SnapshotIterator.
// Remove RInstructionResults from the JitActivation if the frame got recovered
// ahead of the bailout.
class SnapshotIteratorForBailout : public SnapshotIterator
{
RInstructionResults results_;
public:
- SnapshotIteratorForBailout(const IonBailoutIterator &iter)
+ SnapshotIteratorForBailout(const JitFrameIterator &iter)
: SnapshotIterator(iter),
results_(iter.jsFrame())
{
+ MOZ_ASSERT(iter.isBailoutJS());
}
// Take previously computed result out of the activation, or compute the
// results of all recover instructions contained in the snapshot.
bool init(JSContext *cx, JitActivation *activation) {
activation->maybeTakeIonFrameRecovery(fp_, &results_);
if (!results_.isInitialized() && !computeInstructionResults(cx, &results_))
return false;
@@ -1282,17 +1284,17 @@ InitFromBailout(JSContext *cx, HandleScr
MOZ_ASSERT(rectReturnAddr);
if (!builder.writePtr(rectReturnAddr, "ReturnAddr"))
return false;
return true;
}
uint32_t
-jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter,
+jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
bool invalidate, BaselineBailoutInfo **bailoutInfo,
const ExceptionBailoutInfo *excInfo)
{
// The Baseline frames we will reconstruct on the heap are not rooted, so GC
// must be suppressed here.
MOZ_ASSERT(cx->mainThread().suppressGC);
MOZ_ASSERT(bailoutInfo != nullptr);
@@ -1302,17 +1304,17 @@ jit::BailoutIonToBaseline(JSContext *cx,
TraceLogStopEvent(logger, TraceLogger::IonMonkey);
TraceLogStartEvent(logger, TraceLogger::Baseline);
// The caller of the top frame must be one of the following:
// IonJS - Ion calling into Ion.
// BaselineStub - Baseline calling into Ion.
// Entry - Interpreter or other calling into Ion.
// Rectifier - Arguments rectifier calling into Ion.
- MOZ_ASSERT(iter.isIonJS());
+ MOZ_ASSERT(iter.isBailoutJS());
FrameType prevFrameType = iter.prevType();
MOZ_ASSERT(prevFrameType == JitFrame_IonJS ||
prevFrameType == JitFrame_BaselineStub ||
prevFrameType == JitFrame_Entry ||
prevFrameType == JitFrame_Rectifier);
// All incoming frames are going to look like this:
//
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -432,17 +432,17 @@ struct BaselineBailoutInfo
// Number of baseline frames to push on the stack.
uint32_t numFrames;
// The bailout kind.
BailoutKind bailoutKind;
};
uint32_t
-BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter,
+BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
bool invalidate, BaselineBailoutInfo **bailoutInfo,
const ExceptionBailoutInfo *exceptionInfo = nullptr);
// Mark baseline scripts on the stack as active, so that they are not discarded
// during GC.
void
MarkActiveBaselineScripts(Zone *zone);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1293,17 +1293,17 @@ CreateDependentString(MacroAssembler &ma
masm.storePtr(base, Address(string, JSDependentString::offsetOfBase()));
// Follow any base pointer if the input is itself a dependent string.
// Watch for undepended strings, which have a base pointer but don't
// actually share their characters with it.
Label noBase;
masm.branchTest32(Assembler::Zero, Address(base, JSString::offsetOfFlags()),
Imm32(JSString::HAS_BASE_BIT), &noBase);
- masm.branchTest32(Assembler::Zero, Address(base, JSString::offsetOfFlags()),
+ masm.branchTest32(Assembler::NonZero, Address(base, JSString::offsetOfFlags()),
Imm32(JSString::FLAT_BIT), &noBase);
masm.loadPtr(Address(base, JSDependentString::offsetOfBase()), temp1);
masm.storePtr(temp1, Address(string, JSDependentString::offsetOfBase()));
masm.bind(&noBase);
}
masm.bind(&done);
}
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -619,17 +619,17 @@ FinishAllOffThreadCompilations(JSCompart
}
uint8_t *
jit::LazyLinkTopActivation(JSContext *cx)
{
JitActivationIterator iter(cx->runtime());
// First frame should be an exit frame.
- JitFrameIterator it(iter.jitTop(), SequentialExecution);
+ JitFrameIterator it(iter);
MOZ_ASSERT(it.type() == JitFrame_Exit);
// Second frame is the Ion frame.
++it;
MOZ_ASSERT(it.type() == JitFrame_IonJS);
// Get the pending builder from the Ion frame.
IonBuilder *builder = it.script()->ionScript()->pendingBuilder();
@@ -1879,17 +1879,17 @@ AttachFinishedCompilations(JSContext *cx
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
// Try to defer linking if the script is on the stack, to postpone
// invalidating them.
if (builder->info().executionMode() == SequentialExecution &&
builder->script()->hasIonScript())
{
bool onStack = false;
for (JitActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
- for (JitFrameIterator it(iter.jitTop(), SequentialExecution); !it.done(); ++it) {
+ for (JitFrameIterator it(iter); !it.done(); ++it) {
if (!it.isIonJS())
continue;
if (it.checkInvalidation())
continue;
JSScript *script = it.script();
if (builder->script() == script) {
onStack = true;
@@ -2681,35 +2681,42 @@ jit::FastInvoke(JSContext *cx, HandleFun
args.rval().set(result);
MOZ_ASSERT_IF(result.isMagic(), result.isMagic(JS_ION_ERROR));
return result.isMagic() ? IonExec_Error : IonExec_Ok;
}
static void
-InvalidateActivation(FreeOp *fop, uint8_t *jitTop, bool invalidateAll)
+InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool invalidateAll)
{
JitSpew(JitSpew_IonInvalidate, "BEGIN invalidating activation");
size_t frameno = 1;
- for (JitFrameIterator it(jitTop, SequentialExecution); !it.done(); ++it, ++frameno) {
+ for (JitFrameIterator it(activations); !it.done(); ++it, ++frameno) {
MOZ_ASSERT_IF(frameno == 1, it.type() == JitFrame_Exit);
#ifdef DEBUG
switch (it.type()) {
case JitFrame_Exit:
JitSpew(JitSpew_IonInvalidate, "#%d exit frame @ %p", frameno, it.fp());
break;
case JitFrame_BaselineJS:
case JitFrame_IonJS:
+ case JitFrame_Bailout:
{
MOZ_ASSERT(it.isScripted());
- const char *type = it.isIonJS() ? "Optimized" : "Baseline";
+ const char *type = "Unknown";
+ if (it.isIonJS())
+ type = "Optimized";
+ else if (it.isBaselineJS())
+ type = "Baseline";
+ else if (it.isBailoutJS())
+ type = "Bailing";
JitSpew(JitSpew_IonInvalidate, "#%d %s JS frame @ %p, %s:%d (fun: %p, script: %p, pc %p)",
frameno, type, it.fp(), it.script()->filename(), it.script()->lineno(),
it.maybeCallee(), (JSScript *)it.script(), it.returnAddressToFp());
break;
}
case JitFrame_BaselineStub:
JitSpew(JitSpew_IonInvalidate, "#%d baseline stub frame @ %p", frameno, it.fp());
break;
@@ -2836,17 +2843,17 @@ void
jit::InvalidateAll(FreeOp *fop, Zone *zone)
{
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
StopAllOffThreadCompilations(comp);
for (JitActivationIterator iter(fop->runtime()); !iter.done(); ++iter) {
if (iter->compartment()->zone() == zone) {
JitSpew(JitSpew_IonInvalidate, "Invalidating all frames for GC");
- InvalidateActivation(fop, iter.jitTop(), true);
+ InvalidateActivation(fop, iter, true);
}
}
}
void
jit::Invalidate(types::TypeZone &types, FreeOp *fop,
const Vector<types::RecompileInfo> &invalid, bool resetUses,
@@ -2879,17 +2886,17 @@ jit::Invalidate(types::TypeZone &types,
}
if (!numInvalidations) {
JitSpew(JitSpew_IonInvalidate, " No IonScript invalidation.");
return;
}
for (JitActivationIterator iter(fop->runtime()); !iter.done(); ++iter)
- InvalidateActivation(fop, iter.jitTop(), false);
+ InvalidateActivation(fop, iter, false);
// Drop the references added above. If a script was never active, its
// IonScript will be immediately destroyed. Otherwise, it will be held live
// until its last invalidated frame is destroyed.
for (size_t i = 0; i < invalid.length(); i++) {
types::CompilerOutput &co = *invalid[i].compilerOutput(types);
if (!co.isValid())
continue;
@@ -3345,17 +3352,17 @@ AutoDebugModeInvalidation::~AutoDebugMod
// mode.
jit::MarkActiveBaselineScripts(zone);
for (JitActivationIterator iter(rt); !iter.done(); ++iter) {
JSCompartment *comp = iter->compartment();
if (comp_ == comp || zone_ == comp->zone()) {
IonContext ictx(CompileRuntime::get(rt));
JitSpew(JitSpew_IonInvalidate, "Invalidating frames for debug mode toggle");
- InvalidateActivation(fop, iter.jitTop(), true);
+ InvalidateActivation(fop, iter, true);
}
}
for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
if (script->compartment() == comp_ || zone_) {
FinishInvalidation<SequentialExecution>(fop, script);
FinishInvalidation<ParallelExecution>(fop, script);
--- a/js/src/jit/IonFrames-inl.h
+++ b/js/src/jit/IonFrames-inl.h
@@ -75,24 +75,12 @@ GetTopBaselineFrame(JSContext *cx)
MOZ_ASSERT(iter.type() == JitFrame_Exit);
++iter;
if (iter.isBaselineStub())
++iter;
MOZ_ASSERT(iter.isBaselineJS());
return iter.baselineFrame();
}
-inline JSScript *
-GetTopIonJSScript(JSContext *cx, void **returnAddrOut = nullptr)
-{
- return GetTopIonJSScript(cx->mainThread().jitTop, returnAddrOut, SequentialExecution);
-}
-
-inline JSScript *
-GetTopIonJSScript(ForkJoinContext *cx, void **returnAddrOut = nullptr)
-{
- return GetTopIonJSScript(cx->perThreadData->jitTop, returnAddrOut, ParallelExecution);
-}
-
} // namespace jit
} // namespace js
#endif /* jit_IonFrames_inl_h */
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -75,63 +75,58 @@ ReadFrameInt32Slot(IonJSFrameLayout *fp,
}
static inline bool
ReadFrameBooleanSlot(IonJSFrameLayout *fp, int32_t slot)
{
return *(bool *)((char *)fp + OffsetOfFrameSlot(slot));
}
+JitFrameIterator::JitFrameIterator()
+ : current_(nullptr),
+ type_(JitFrame_Exit),
+ returnAddressToFp_(nullptr),
+ frameSize_(0),
+ mode_(SequentialExecution),
+ cachedSafepointIndex_(nullptr),
+ activation_(nullptr)
+{
+}
+
JitFrameIterator::JitFrameIterator(ThreadSafeContext *cx)
: current_(cx->perThreadData->jitTop),
type_(JitFrame_Exit),
returnAddressToFp_(nullptr),
frameSize_(0),
mode_(cx->isForkJoinContext() ? ParallelExecution : SequentialExecution),
- kind_(Kind_FrameIterator),
cachedSafepointIndex_(nullptr),
- activation_(nullptr)
+ activation_(cx->perThreadData->activation()->asJit())
{
+ if (activation_->bailoutData()) {
+ current_ = activation_->bailoutData()->fp();
+ frameSize_ = activation_->bailoutData()->topFrameSize();
+ type_ = JitFrame_Bailout;
+ }
}
JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
: current_(activations.jitTop()),
type_(JitFrame_Exit),
returnAddressToFp_(nullptr),
frameSize_(0),
mode_(activations->asJit()->cx()->isForkJoinContext() ? ParallelExecution
: SequentialExecution),
- kind_(Kind_FrameIterator),
cachedSafepointIndex_(nullptr),
activation_(activations->asJit())
{
-}
-
-JitFrameIterator::JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode)
- : current_((uint8_t *)fp),
- type_(JitFrame_IonJS),
- returnAddressToFp_(fp->returnAddress()),
- frameSize_(fp->prevFrameLocalSize()),
- mode_(mode),
- kind_(Kind_FrameIterator)
-{
-}
-
-IonBailoutIterator *
-JitFrameIterator::asBailoutIterator()
-{
- MOZ_ASSERT(isBailoutIterator());
- return static_cast<IonBailoutIterator *>(this);
-}
-
-const IonBailoutIterator *
-JitFrameIterator::asBailoutIterator() const
-{
- MOZ_ASSERT(isBailoutIterator());
- return static_cast<const IonBailoutIterator *>(this);
+ if (activation_->bailoutData()) {
+ current_ = activation_->bailoutData()->fp();
+ frameSize_ = activation_->bailoutData()->topFrameSize();
+ type_ = JitFrame_Bailout;
+ }
}
bool
JitFrameIterator::checkInvalidation() const
{
IonScript *dummy;
return checkInvalidation(&dummy);
}
@@ -268,16 +263,17 @@ JitFrameIterator::actualArgs() const
static inline size_t
SizeOfFramePrefix(FrameType type)
{
switch (type) {
case JitFrame_Entry:
return IonEntryFrameLayout::Size();
case JitFrame_BaselineJS:
case JitFrame_IonJS:
+ case JitFrame_Bailout:
case JitFrame_Unwound_IonJS:
return IonJSFrameLayout::Size();
case JitFrame_BaselineStub:
return IonBaselineStubFrameLayout::Size();
case JitFrame_Rectifier:
return IonRectifierFrameLayout::Size();
case JitFrame_Unwound_Rectifier:
return IonUnwoundRectifierFrameLayout::Size();
@@ -332,26 +328,34 @@ JitFrameIterator::operator++()
return *this;
}
uintptr_t *
JitFrameIterator::spillBase() const
{
+ MOZ_ASSERT(isIonJS());
+
// Get the base address to where safepoint registers are spilled.
// Out-of-line calls do not unwind the extra padding space used to
// aggregate bailout tables, so we use frameSize instead of frameLocals,
// which would only account for local stack slots.
return reinterpret_cast<uintptr_t *>(fp() - ionScript()->frameSize());
}
MachineState
JitFrameIterator::machineState() const
{
+ MOZ_ASSERT(isIonScripted());
+
+ // The MachineState is used by GCs for marking call-sites.
+ if (MOZ_UNLIKELY(isBailoutJS()))
+ return activation_->bailoutData()->machineState();
+
SafepointReader reader(ionScript(), safepoint());
uintptr_t *spill = spillBase();
MachineState machine;
for (GeneralRegisterBackwardIterator iter(reader.allGprSpills()); iter.more(); iter++)
machine.setRegisterLocation(*iter, --spill);
uint8_t *spillAlign = alignDoubleSpillWithOffset(reinterpret_cast<uint8_t *>(spill), 0);
@@ -1030,17 +1034,17 @@ MarkBaselineStubFrame(JSTracer *trc, con
MOZ_ASSERT(ICStub::CanMakeCalls(stub->kind()));
stub->trace(trc);
}
}
void
JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end)
{
- JitFrameIterator frames(jitTop(), SequentialExecution);
+ JitFrameIterator frames(*this);
if (frames.isFakeExitFrame()) {
min = reinterpret_cast<uintptr_t *>(frames.fp());
} else {
IonExitFrameLayout *exitFrame = frames.exitFrame();
IonExitFooterFrame *footer = exitFrame->footer();
const VMFunction *f = footer->function();
if (exitFrame->isWrapperExit() && f->outParam == Type_Handle) {
@@ -1361,17 +1365,18 @@ void UpdateJitActivationsForMinorGC<gc::
void
GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
{
JitSpew(JitSpew_IonSnapshots, "Recover PC & Script from the last frame.");
JSRuntime *rt = cx->runtime();
// Recover the return address.
- JitFrameIterator it(rt->mainThread.jitTop, SequentialExecution);
+ JitActivationIterator iter(rt);
+ JitFrameIterator it(iter);
// If the previous frame is a rectifier frame (maybe unwound),
// skip past it.
if (it.prevType() == JitFrame_Rectifier || it.prevType() == JitFrame_Unwound_Rectifier) {
++it;
MOZ_ASSERT(it.prevType() == JitFrame_BaselineStub ||
it.prevType() == JitFrame_BaselineJS ||
it.prevType() == JitFrame_IonJS);
@@ -1524,17 +1529,17 @@ SnapshotIterator::SnapshotIterator(IonSc
ionScript_(ionScript),
instructionResults_(nullptr)
{
MOZ_ASSERT(snapshotOffset < ionScript->snapshotsListSize());
}
SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter)
: snapshot_(iter.ionScript()->snapshots(),
- iter.osiIndex()->snapshotOffset(),
+ iter.snapshotOffset(),
iter.ionScript()->snapshotsRVATableSize(),
iter.ionScript()->snapshotsListSize()),
recover_(snapshot_,
iter.ionScript()->recovers(),
iter.ionScript()->recoversSize()),
fp_(iter.jsFrame()),
machine_(iter.machineState()),
ionScript_(iter.ionScript()),
@@ -1908,54 +1913,77 @@ SnapshotIterator::maybeReadAllocByIndex(
}
while (moreAllocations())
skip();
return s;
}
+IonJSFrameLayout *
+JitFrameIterator::jsFrame() const
+{
+ MOZ_ASSERT(isScripted());
+ if (isBailoutJS())
+ return (IonJSFrameLayout *) activation_->bailoutData()->fp();
+
+ return (IonJSFrameLayout *) fp();
+}
+
IonScript *
JitFrameIterator::ionScript() const
{
- MOZ_ASSERT(type() == JitFrame_IonJS);
+ MOZ_ASSERT(isIonScripted());
+ if (isBailoutJS())
+ return activation_->bailoutData()->ionScript();
IonScript *ionScript = nullptr;
if (checkInvalidation(&ionScript))
return ionScript;
return ionScriptFromCalleeToken();
}
IonScript *
JitFrameIterator::ionScriptFromCalleeToken() const
{
- MOZ_ASSERT(type() == JitFrame_IonJS);
+ MOZ_ASSERT(isIonJS());
MOZ_ASSERT(!checkInvalidation());
switch (mode_) {
case SequentialExecution:
return script()->ionScript();
case ParallelExecution:
return script()->parallelIonScript();
default:
MOZ_CRASH("No such execution mode");
}
}
const SafepointIndex *
JitFrameIterator::safepoint() const
{
+ MOZ_ASSERT(isIonJS());
if (!cachedSafepointIndex_)
cachedSafepointIndex_ = ionScript()->getSafepointIndex(returnAddressToFp());
return cachedSafepointIndex_;
}
+SnapshotOffset
+JitFrameIterator::snapshotOffset() const
+{
+ MOZ_ASSERT(isIonScripted());
+ if (isBailoutJS())
+ return activation_->bailoutData()->snapshotOffset();
+ return osiIndex()->snapshotOffset();
+}
+
const OsiIndex *
JitFrameIterator::osiIndex() const
{
+ MOZ_ASSERT(isIonJS());
SafepointReader reader(ionScript(), safepoint());
return ionScript()->getOsiIndex(reader.osiReturnPointOffset());
}
InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter)
: callee_(cx),
script_(cx)
{
@@ -1964,41 +1992,25 @@ InlineFrameIterator::InlineFrameIterator
InlineFrameIterator::InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter)
: callee_(rt),
script_(rt)
{
resetOn(iter);
}
-InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const IonBailoutIterator *iter)
- : frame_(iter),
- framesRead_(0),
- frameCount_(UINT32_MAX),
- callee_(cx),
- script_(cx)
-{
- if (iter) {
- start_ = SnapshotIterator(*iter);
- findNextFrame();
- }
-}
-
InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const InlineFrameIterator *iter)
: frame_(iter ? iter->frame_ : nullptr),
framesRead_(0),
frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
callee_(cx),
script_(cx)
{
if (frame_) {
- if (frame_->isBailoutIterator())
- start_ = SnapshotIterator(*frame_->asBailoutIterator());
- else
- start_ = SnapshotIterator(*frame_);
+ start_ = SnapshotIterator(*frame_);
// findNextFrame will iterate to the next frame and init. everything.
// Therefore to settle on the same frame, we report one frame less readed.
framesRead_ = iter->framesRead_ - 1;
findNextFrame();
}
}
@@ -2327,16 +2339,17 @@ JitFrameIterator::dump() const
case JitFrame_BaselineJS:
dumpBaseline();
break;
case JitFrame_BaselineStub:
case JitFrame_Unwound_BaselineStub:
fprintf(stderr, " Baseline stub frame\n");
fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
break;
+ case JitFrame_Bailout:
case JitFrame_IonJS:
{
InlineFrameIterator frames(GetJSContextFromJitCode(), this);
for (;;) {
frames.dump();
if (!frames.more())
break;
++frames;
--- a/js/src/jit/IonFrames.h
+++ b/js/src/jit/IonFrames.h
@@ -287,19 +287,19 @@ void UpdateJitActivationsForMinorGC(PerT
static inline uint32_t
MakeFrameDescriptor(uint32_t frameSize, FrameType type)
{
return (frameSize << FRAMESIZE_SHIFT) | type;
}
// Returns the JSScript associated with the topmost Ion frame.
inline JSScript *
-GetTopIonJSScript(uint8_t *jitTop, void **returnAddrOut, ExecutionMode mode)
+GetTopIonJSScript(ThreadSafeContext *cx, void **returnAddrOut = nullptr)
{
- JitFrameIterator iter(jitTop, mode);
+ JitFrameIterator iter(cx);
MOZ_ASSERT(iter.type() == JitFrame_Exit);
++iter;
MOZ_ASSERT(iter.returnAddressToFp() != nullptr);
if (returnAddrOut)
*returnAddrOut = (void *) iter.returnAddressToFp();
if (iter.isBaselineStub()) {
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -52,79 +52,63 @@ enum FrameType
// An unwound rectifier frame is a rectifier frame signalling that its callee
// frame has been turned into an exit frame (see EnsureExitFrame).
JitFrame_Unwound_Rectifier,
// An exit frame is necessary for transitioning from a JS frame into C++.
// From within C++, an exit frame is always the last frame in any
// JitActivation.
- JitFrame_Exit
+ JitFrame_Exit,
+
+ // A bailout frame is a special IonJS jit frame after a bailout, and before
+ // the reconstruction of the BaselineJS frame. From within C++, a bailout
+ // frame is always the last frame in a JitActivation iff the bailout frame
+ // information is recorded on the JitActivation.
+ JitFrame_Bailout
};
enum ReadFrameArgsBehavior {
// Only read formals (i.e. [0 ... callee()->nargs]
ReadFrame_Formals,
// Only read overflown args (i.e. [callee()->nargs ... numActuals()]
ReadFrame_Overflown,
// Read all args (i.e. [0 ... numActuals()])
ReadFrame_Actuals
};
class IonCommonFrameLayout;
class IonJSFrameLayout;
class IonExitFrameLayout;
-class IonBailoutIterator;
class BaselineFrame;
class JitActivation;
class JitFrameIterator
{
protected:
uint8_t *current_;
FrameType type_;
uint8_t *returnAddressToFp_;
size_t frameSize_;
ExecutionMode mode_;
- enum Kind {
- Kind_FrameIterator,
- Kind_BailoutIterator
- } kind_;
private:
mutable const SafepointIndex *cachedSafepointIndex_;
const JitActivation *activation_;
void dumpBaseline() const;
public:
- explicit JitFrameIterator(uint8_t *top, ExecutionMode mode)
- : current_(top),
- type_(JitFrame_Exit),
- returnAddressToFp_(nullptr),
- frameSize_(0),
- mode_(mode),
- kind_(Kind_FrameIterator),
- cachedSafepointIndex_(nullptr),
- activation_(nullptr)
- { }
-
+ explicit JitFrameIterator();
explicit JitFrameIterator(ThreadSafeContext *cx);
explicit JitFrameIterator(const ActivationIterator &activations);
- explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode);
-
- bool isBailoutIterator() const {
- return kind_ == Kind_BailoutIterator;
- }
- IonBailoutIterator *asBailoutIterator();
- const IonBailoutIterator *asBailoutIterator() const;
// Current frame information.
FrameType type() const {
return type_;
}
uint8_t *fp() const {
return current_;
}
@@ -133,40 +117,45 @@ class JitFrameIterator
}
IonCommonFrameLayout *current() const {
return (IonCommonFrameLayout *)current_;
}
inline uint8_t *returnAddress() const;
- IonJSFrameLayout *jsFrame() const {
- MOZ_ASSERT(isScripted());
- return (IonJSFrameLayout *) fp();
- }
+ // Return the pointer of the JitFrame, the iterator is assumed to be settled
+ // on a scripted frame.
+ IonJSFrameLayout *jsFrame() const;
// Returns true iff this exit frame was created using EnsureExitFrame.
inline bool isFakeExitFrame() const;
inline IonExitFrameLayout *exitFrame() const;
// Returns whether the JS frame has been invalidated and, if so,
// places the invalidated Ion script in |ionScript|.
bool checkInvalidation(IonScript **ionScript) const;
bool checkInvalidation() const;
bool isScripted() const {
- return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS;
+ return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
}
bool isBaselineJS() const {
return type_ == JitFrame_BaselineJS;
}
+ bool isIonScripted() const {
+ return type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
+ }
bool isIonJS() const {
return type_ == JitFrame_IonJS;
}
+ bool isBailoutJS() const {
+ return type_ == JitFrame_Bailout;
+ }
bool isBaselineStub() const {
return type_ == JitFrame_BaselineStub;
}
bool isBareExit() const;
template <typename T> bool isExitFrameLayout() const;
bool isEntry() const {
return type_ == JitFrame_Entry;
@@ -222,16 +211,20 @@ class JitFrameIterator
// Returns the Safepoint associated with this JS frame. Incurs a lookup
// overhead.
const SafepointIndex *safepoint() const;
// Returns the OSI index associated with this JS frame. Incurs a lookup
// overhead.
const OsiIndex *osiIndex() const;
+ // Returns the Snapshot offset associated with this JS frame. Incurs a
+ // lookup overhead.
+ SnapshotOffset snapshotOffset() const;
+
uintptr_t *spillBase() const;
MachineState machineState() const;
template <class Op>
void unaliasedForEachActual(Op op, ReadFrameArgsBehavior behavior) const {
MOZ_ASSERT(isBaselineJS());
unsigned nactual = numActualArgs();
@@ -471,17 +464,16 @@ class SnapshotIterator
public:
// Connect all informations about the current script in order to recover the
// content of baseline frames.
SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
IonJSFrameLayout *fp, const MachineState &machine);
explicit SnapshotIterator(const JitFrameIterator &iter);
- explicit SnapshotIterator(const IonBailoutIterator &iter);
SnapshotIterator();
Value read() {
return allocationValue(readAllocation());
}
Value maybeRead(MaybeReadFallback &fallback) {
RValueAllocation a = readAllocation();
@@ -586,17 +578,16 @@ class InlineFrameIterator
private:
void findNextFrame();
JSObject *computeScopeChain(Value scopeChainValue) const;
public:
InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter);
InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter);
- InlineFrameIterator(ThreadSafeContext *cx, const IonBailoutIterator *iter);
InlineFrameIterator(ThreadSafeContext *cx, const InlineFrameIterator *iter);
bool more() const {
return frame_ && framesRead_ < frameCount_;
}
JSFunction *callee() const {
MOZ_ASSERT(callee_);
return callee_;
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -539,17 +539,18 @@ jit::BailoutPar(BailoutStack *sp, uint8_
// We don't have an exit frame.
MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
"Fake jitTop pointer should be within the first page.");
cx->perThreadData->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
JitActivationIterator jitActivations(cx->perThreadData);
- IonBailoutIterator frameIter(jitActivations, sp);
+ BailoutFrameInfo bailoutData(jitActivations, sp);
+ JitFrameIterator frameIter(jitActivations);
SnapshotIterator snapIter(frameIter);
cx->bailoutRecord->setIonBailoutKind(snapIter.bailoutKind());
cx->bailoutRecord->rematerializeFrames(cx, frameIter);
MOZ_ASSERT(frameIter.done());
*entryFramePointer = frameIter.fp();
}
--- a/js/src/jit/arm/Bailouts-arm.cpp
+++ b/js/src/jit/arm/Bailouts-arm.cpp
@@ -64,63 +64,59 @@ class BailoutStack
};
// Make sure the compiler doesn't add extra padding.
static_assert((sizeof(BailoutStack) % 8) == 0, "BailoutStack should be 8-byte aligned.");
} // namespace jit
} // namespace js
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
- BailoutStack *bailout)
- : JitFrameIterator(activations),
- machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+ BailoutStack *bailout)
+ : machine_(bailout->machine())
{
uint8_t *sp = bailout->parentStackPointer();
- uint8_t *fp = sp + bailout->frameSize();
+ framePointer_ = sp + bailout->frameSize();
+ topFrameSize_ = framePointer_ - sp;
- kind_ = Kind_BailoutIterator;
- current_ = fp;
- type_ = JitFrame_IonJS;
- topFrameSize_ = current_ - sp;
- switch (mode_) {
- case SequentialExecution: topIonScript_ = script()->ionScript(); break;
- case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
- default: MOZ_CRASH("No such execution mode");
- }
+ JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+ JitActivation *activation = activations.activation()->asJit();
+ if (activation->cx()->isForkJoinContext())
+ topIonScript_ = script->parallelIonScript();
+ else
+ topIonScript_ = script->ionScript();
+
+ attachOnJitActivation(activations);
if (bailout->frameClass() == FrameSizeClass::None()) {
snapshotOffset_ = bailout->snapshotOffset();
return;
}
// Compute the snapshot offset from the bailout ID.
- JitActivation *activation = activations.activation()->asJit();
JSRuntime *rt = activation->compartment()->runtimeFromMainThread();
JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
uintptr_t tableOffset = bailout->tableOffset();
uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code->raw()));
MOZ_ASSERT(tableOffset >= tableStart &&
tableOffset < tableStart + code->instructionsSize());
MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE);
snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId);
}
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
- InvalidationBailoutStack *bailout)
- : JitFrameIterator(activations),
- machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+ InvalidationBailoutStack *bailout)
+ : machine_(bailout->machine())
{
- kind_ = Kind_BailoutIterator;
- returnAddressToFp_ = bailout->osiPointReturnAddress();
+ framePointer_ = (uint8_t*) bailout->fp();
+ topFrameSize_ = framePointer_ - bailout->sp();
topIonScript_ = bailout->ionScript();
+ attachOnJitActivation(activations);
+
+ uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
- current_ = (uint8_t*) bailout->fp();
- type_ = JitFrame_IonJS;
- topFrameSize_ = current_ - bailout->sp();
snapshotOffset_ = osiIndex->snapshotOffset();
}
--- a/js/src/jit/mips/Bailouts-mips.cpp
+++ b/js/src/jit/mips/Bailouts-mips.cpp
@@ -7,63 +7,59 @@
#include "jit/mips/Bailouts-mips.h"
#include "jscntxt.h"
#include "jscompartment.h"
using namespace js;
using namespace js::jit;
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
- BailoutStack *bailout)
- : JitFrameIterator(activations),
- machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+ BailoutStack *bailout)
+ : machine_(bailout->machine())
{
uint8_t *sp = bailout->parentStackPointer();
- uint8_t *fp = sp + bailout->frameSize();
+ framePointer_ = sp + bailout->frameSize();
+ topFrameSize_ = framePointer_ - sp;
- kind_ = Kind_BailoutIterator;
- current_ = fp;
- type_ = JitFrame_IonJS;
- topFrameSize_ = current_ - sp;
- switch (mode_) {
- case SequentialExecution: topIonScript_ = script()->ionScript(); break;
- case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
- default: MOZ_CRASH("No such execution mode");
- }
+ JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+ JitActivation *activation = activations.activation()->asJit();
+ if (activation->cx()->isForkJoinContext())
+ topIonScript_ = script->parallelIonScript();
+ else
+ topIonScript_ = script->ionScript();
+
+ attachOnJitActivation(activations);
if (bailout->frameClass() == FrameSizeClass::None()) {
snapshotOffset_ = bailout->snapshotOffset();
return;
}
// Compute the snapshot offset from the bailout ID.
- JitActivation *activation = activations.activation()->asJit();
JSRuntime *rt = activation->compartment()->runtimeFromMainThread();
JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
uintptr_t tableOffset = bailout->tableOffset();
uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
MOZ_ASSERT(tableOffset >= tableStart &&
- tableOffset < tableStart + code->instructionsSize());
+ tableOffset < tableStart + code->instructionsSize());
MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE);
snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId);
}
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
- InvalidationBailoutStack *bailout)
- : JitFrameIterator(activations),
- machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+ InvalidationBailoutStack *bailout)
+ : machine_(bailout->machine())
{
- kind_ = Kind_BailoutIterator;
- returnAddressToFp_ = bailout->osiPointReturnAddress();
+ framePointer_ = (uint8_t*) bailout->fp();
+ topFrameSize_ = framePointer_ - bailout->sp();
topIonScript_ = bailout->ionScript();
+ attachOnJitActivation(activations);
+
+ uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
- current_ = (uint8_t*) bailout->fp();
- type_ = JitFrame_IonJS;
- topFrameSize_ = current_ - bailout->sp();
snapshotOffset_ = osiIndex->snapshotOffset();
}
--- a/js/src/jit/none/Trampoline-none.cpp
+++ b/js/src/jit/none/Trampoline-none.cpp
@@ -42,24 +42,22 @@ void MacroAssembler::alignFrameForICArgu
void MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive &) { MOZ_CRASH(); }
const Register ABIArgGenerator::NonArgReturnReg0 = { 0 };
const Register ABIArgGenerator::NonArgReturnReg1 = { 0 };
const Register ABIArgGenerator::NonArg_VolatileReg = { 0 };
const Register ABIArgGenerator::NonReturn_VolatileReg0 = { 0 };
const Register ABIArgGenerator::NonReturn_VolatileReg1 = { 0 };
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &iter, BailoutStack *bailout)
- : JitFrameIterator(iter)
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &iter, BailoutStack *bailout)
{
MOZ_CRASH();
}
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &iter, InvalidationBailoutStack *bailout)
- : JitFrameIterator(iter)
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &iter, InvalidationBailoutStack *bailout)
{
MOZ_CRASH();
}
bool ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
bool ICCompare_Double::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
bool ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
--- a/js/src/jit/x64/Bailouts-x64.cpp
+++ b/js/src/jit/x64/Bailouts-x64.cpp
@@ -40,43 +40,40 @@ class BailoutStack
} // namespace jit
} // namespace js
#if defined(_WIN32)
# pragma pack(pop)
#endif
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
- BailoutStack *bailout)
- : JitFrameIterator(activations),
- machine_(bailout->machineState())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+ BailoutStack *bailout)
+ : machine_(bailout->machineState())
{
uint8_t *sp = bailout->parentStackPointer();
- uint8_t *fp = sp + bailout->frameSize();
+ framePointer_ = sp + bailout->frameSize();
+ topFrameSize_ = framePointer_ - sp;
- kind_ = Kind_BailoutIterator;
- current_ = fp;
- type_ = JitFrame_IonJS;
- topFrameSize_ = current_ - sp;
- switch (mode_) {
- case SequentialExecution: topIonScript_ = script()->ionScript(); break;
- case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
- default: MOZ_CRASH("No such execution mode");
- }
+ JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+ JitActivation *activation = activations.activation()->asJit();
+ if (activation->cx()->isForkJoinContext())
+ topIonScript_ = script->parallelIonScript();
+ else
+ topIonScript_ = script->ionScript();
+
+ attachOnJitActivation(activations);
snapshotOffset_ = bailout->snapshotOffset();
}
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
- InvalidationBailoutStack *bailout)
- : JitFrameIterator(activations),
- machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+ InvalidationBailoutStack *bailout)
+ : machine_(bailout->machine())
{
- kind_ = Kind_BailoutIterator;
- returnAddressToFp_ = bailout->osiPointReturnAddress();
+ framePointer_ = (uint8_t*) bailout->fp();
+ topFrameSize_ = framePointer_ - bailout->sp();
topIonScript_ = bailout->ionScript();
+ attachOnJitActivation(activations);
+
+ uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
- current_ = (uint8_t*) bailout->fp();
- type_ = JitFrame_IonJS;
- topFrameSize_ = current_ - bailout->sp();
snapshotOffset_ = osiIndex->snapshotOffset();
}
--- a/js/src/jit/x86/Bailouts-x86.cpp
+++ b/js/src/jit/x86/Bailouts-x86.cpp
@@ -60,63 +60,59 @@ class BailoutStack
} // namespace jit
} // namespace js
#if defined(_WIN32)
# pragma pack(pop)
#endif
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
- BailoutStack *bailout)
- : JitFrameIterator(activations),
- machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+ BailoutStack *bailout)
+ : machine_(bailout->machine())
{
uint8_t *sp = bailout->parentStackPointer();
- uint8_t *fp = sp + bailout->frameSize();
+ framePointer_ = sp + bailout->frameSize();
+ topFrameSize_ = framePointer_ - sp;
- kind_ = Kind_BailoutIterator;
- current_ = fp;
- type_ = JitFrame_IonJS;
- topFrameSize_ = current_ - sp;
- switch (mode_) {
- case SequentialExecution: topIonScript_ = script()->ionScript(); break;
- case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
- default: MOZ_CRASH("No such execution mode");
- }
+ JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+ JitActivation *activation = activations.activation()->asJit();
+ if (activation->cx()->isForkJoinContext())
+ topIonScript_ = script->parallelIonScript();
+ else
+ topIonScript_ = script->ionScript();
+
+ attachOnJitActivation(activations);
if (bailout->frameClass() == FrameSizeClass::None()) {
snapshotOffset_ = bailout->snapshotOffset();
return;
}
// Compute the snapshot offset from the bailout ID.
- JitActivation *activation = activations.activation()->asJit();
JSRuntime *rt = activation->compartment()->runtimeFromMainThread();
JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
uintptr_t tableOffset = bailout->tableOffset();
uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
MOZ_ASSERT(tableOffset >= tableStart &&
tableOffset < tableStart + code->instructionsSize());
MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE);
snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId);
}
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
- InvalidationBailoutStack *bailout)
- : JitFrameIterator(activations),
- machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+ InvalidationBailoutStack *bailout)
+ : machine_(bailout->machine())
{
- kind_ = Kind_BailoutIterator;
- returnAddressToFp_ = bailout->osiPointReturnAddress();
+ framePointer_ = (uint8_t*) bailout->fp();
+ topFrameSize_ = framePointer_ - bailout->sp();
topIonScript_ = bailout->ionScript();
+ attachOnJitActivation(activations);
+
+ uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
- current_ = (uint8_t*) bailout->fp();
- type_ = JitFrame_IonJS;
- topFrameSize_ = current_ - bailout->sp();
snapshotOffset_ = osiIndex->snapshotOffset();
}
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -377,21 +377,28 @@ js::GetOwnPropertyDescriptor(JSContext *
desc.object().set(nullptr);
return true;
}
bool doGet = true;
if (pobj->isNative()) {
desc.setAttributes(GetShapeAttributes(pobj, shape));
if (desc.hasGetterOrSetterObject()) {
+ MOZ_ASSERT(desc.isShared());
doGet = false;
if (desc.hasGetterObject())
desc.setGetterObject(shape->getterObject());
if (desc.hasSetterObject())
desc.setSetterObject(shape->setterObject());
+ } else {
+ // This is either a straight-up data property or (rarely) a
+ // property with a JSPropertyOp getter/setter. The latter must be
+ // reported to the caller as a plain data property, so don't
+ // populate desc.getter/setter, and mask away the SHARED bit.
+ desc.attributesRef() &= ~JSPROP_SHARED;
}
} else {
if (!JSObject::getGenericAttributes(cx, pobj, id, &desc.attributesRef()))
return false;
}
RootedValue value(cx);
if (doGet && !JSObject::getGeneric(cx, obj, obj, id, &value))
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1225,22 +1225,22 @@ class JSScript : public js::gc::TenuredC
// so it can only transition from not being a generator.
MOZ_ASSERT(!isGenerator());
generatorKindBits_ = GeneratorKindAsBits(kind);
}
/*
* As an optimization, even when argsHasLocalBinding, the function prologue
* may not need to create an arguments object. This is determined by
- * needsArgsObj which is set by AnalyzeArgumentsUsage before running
- * the script the first time. When !needsArgsObj, the prologue may simply
- * write MagicValue(JS_OPTIMIZED_ARGUMENTS) to 'arguments's slot and any
- * uses of 'arguments' will be guaranteed to handle this magic value.
- * So avoid spurious arguments object creation, we maintain the invariant
- * that needsArgsObj is only called after the script has been analyzed.
+ * needsArgsObj which is set by AnalyzeArgumentsUsage. When !needsArgsObj,
+ * the prologue may simply write MagicValue(JS_OPTIMIZED_ARGUMENTS) to
+ * 'arguments's slot and any uses of 'arguments' will be guaranteed to
+ * handle this magic value. To avoid spurious arguments object creation, we
+ * maintain the invariant that needsArgsObj is only called after the script
+ * has been analyzed.
*/
bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
inline bool ensureHasAnalyzedArgsUsage(JSContext *cx);
bool needsArgsObj() const {
MOZ_ASSERT(analyzedArgsUsage());
return needsArgsObj_;
}
void setNeedsArgsObj(bool needsArgsObj);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4615,16 +4615,18 @@ DebuggerArguments_getArg(JSContext *cx,
* Since getters can be extracted and applied to other objects,
* there is no guarantee this object has an ith argument.
*/
MOZ_ASSERT(i >= 0);
RootedValue arg(cx);
RootedScript script(cx);
if (unsigned(i) < frame.numActualArgs()) {
script = frame.script();
+ if (!script->ensureHasAnalyzedArgsUsage(cx))
+ return false;
if (unsigned(i) < frame.numFormalArgs() && script->formalIsAliased(i)) {
for (AliasedFormalIter fi(script); ; fi++) {
if (fi.frameIndex() == unsigned(i)) {
arg = frame.callObj().aliasedVar(fi);
break;
}
}
} else if (script->argsObjAliasesFormals() && frame.hasArgsObj()) {
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -1876,66 +1876,51 @@ ParallelBailoutRecord::init(JSContext *c
void
ParallelBailoutRecord::reset()
{
RematerializedFrame::FreeInVector(frames());
cause = ParallelBailoutNone;
}
-template <class T>
-static void
-RematerializeFramesWithIter(ForkJoinContext *cx, T &frameIter,
- Vector<RematerializedFrame *> &frames)
+void
+ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, JitFrameIterator &frameIter)
{
- // This function as well as |rematerializeFrames| methods below are
- // infallible. These are only called when we are already erroring out. If
- // we OOM here, free what we've allocated and return. Error reporting is
- // then unable to give the user detailed stack information.
+ // This function is infallible. These are only called when we are already
+ // erroring out. If we OOM here, free what we've allocated and return. Error
+ // reporting is then unable to give the user detailed stack information.
- MOZ_ASSERT(frames.empty());
+ MOZ_ASSERT(frames().empty());
for (; !frameIter.done(); ++frameIter) {
if (!frameIter.isIonJS())
continue;
InlineFrameIterator inlineIter(cx, &frameIter);
Vector<RematerializedFrame *> inlineFrames(cx);
if (!RematerializedFrame::RematerializeInlineFrames(cx, frameIter.fp(),
inlineIter, inlineFrames))
{
RematerializedFrame::FreeInVector(inlineFrames);
- RematerializedFrame::FreeInVector(frames);
+ RematerializedFrame::FreeInVector(frames());
return;
}
// Reverse the inline frames into the main vector.
while (!inlineFrames.empty()) {
- if (!frames.append(inlineFrames.popCopy())) {
+ if (!frames().append(inlineFrames.popCopy())) {
RematerializedFrame::FreeInVector(inlineFrames);
- RematerializedFrame::FreeInVector(frames);
+ RematerializedFrame::FreeInVector(frames());
return;
}
}
}
}
-void
-ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, JitFrameIterator &frameIter)
-{
- RematerializeFramesWithIter(cx, frameIter, frames());
-}
-
-void
-ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, IonBailoutIterator &frameIter)
-{
- RematerializeFramesWithIter(cx, frameIter, frames());
-}
-
//////////////////////////////////////////////////////////////////////////////
//
// Debug spew
//
#ifdef FORKJOIN_SPEW
--- a/js/src/vm/ForkJoin.h
+++ b/js/src/vm/ForkJoin.h
@@ -321,17 +321,16 @@ enum ParallelBailoutCause {
// parallel.
ParallelBailoutRequestedGC,
ParallelBailoutRequestedZoneGC
};
namespace jit {
class BailoutStack;
class JitFrameIterator;
-class IonBailoutIterator;
class RematerializedFrame;
}
// See "Bailouts" section in comment above.
struct ParallelBailoutRecord
{
// Captured Ion frames at the point of bailout. Stored younger-to-older,
// i.e., the 0th frame is the youngest frame.
@@ -368,17 +367,16 @@ struct ParallelBailoutRecord
}
void setIonBailoutKind(jit::BailoutKind kind) {
joinCause(ParallelBailoutExecution);
ionBailoutKind = kind;
}
void rematerializeFrames(ForkJoinContext *cx, jit::JitFrameIterator &frameIter);
- void rematerializeFrames(ForkJoinContext *cx, jit::IonBailoutIterator &frameIter);
};
class ForkJoinShared;
class ForkJoinContext : public ThreadSafeContext
{
public:
// Bailout record used to record the reason this thread stopped executing
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -450,24 +450,25 @@ RegExpShared::trace(JSTracer *trc)
for (size_t i = 0; i < ArrayLength(compilationArray); i++) {
RegExpCompilation &compilation = compilationArray[i];
if (compilation.jitCode)
MarkJitCode(trc, &compilation.jitCode, "RegExpShared code");
}
}
bool
-RegExpShared::compile(JSContext *cx, HandleLinearString input, CompilationMode mode)
+RegExpShared::compile(JSContext *cx, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force)
{
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
AutoTraceLog logCompile(logger, TraceLogger::IrregexpCompile);
if (!sticky()) {
RootedAtom pattern(cx, source);
- return compile(cx, pattern, input, mode);
+ return compile(cx, pattern, input, mode, force);
}
/*
* The sticky case we implement hackily by prepending a caret onto the front
* and relying on |::execute| to pseudo-slice the string when it sees a sticky regexp.
*/
static const char prefix[] = {'^', '(', '?', ':'};
static const char postfix[] = {')'};
@@ -480,22 +481,22 @@ RegExpShared::compile(JSContext *cx, Han
if (!sb.append(source))
return false;
sb.infallibleAppend(postfix, ArrayLength(postfix));
RootedAtom fakeySource(cx, sb.finishAtom());
if (!fakeySource)
return false;
- return compile(cx, fakeySource, input, mode);
+ return compile(cx, fakeySource, input, mode, force);
}
bool
RegExpShared::compile(JSContext *cx, HandleAtom pattern, HandleLinearString input,
- CompilationMode mode)
+ CompilationMode mode, ForceByteCodeEnum force)
{
if (!ignoreCase() && !StringHasRegExpMetaChars(pattern)) {
canStringMatch = true;
parenCount = 0;
return true;
}
CompileOptions options(cx);
@@ -512,47 +513,52 @@ RegExpShared::compile(JSContext *cx, Han
}
this->parenCount = data.capture_count;
irregexp::RegExpCode code = irregexp::CompilePattern(cx, this, &data, input,
false /* global() */,
ignoreCase(),
input->hasLatin1Chars(),
- mode == MatchOnly);
+ mode == MatchOnly,
+ force == ForceByteCode);
if (code.empty())
return false;
MOZ_ASSERT(!code.jitCode || !code.byteCode);
+ MOZ_ASSERT_IF(force == ForceByteCode, code.byteCode);
RegExpCompilation &compilation = this->compilation(mode, input->hasLatin1Chars());
- compilation.jitCode = code.jitCode;
- compilation.byteCode = code.byteCode;
+ if (code.jitCode)
+ compilation.jitCode = code.jitCode;
+ else if (code.byteCode)
+ compilation.byteCode = code.byteCode;
return true;
}
bool
-RegExpShared::compileIfNecessary(JSContext *cx, HandleLinearString input, CompilationMode mode)
+RegExpShared::compileIfNecessary(JSContext *cx, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force)
{
- if (isCompiled(mode, input->hasLatin1Chars()) || canStringMatch)
+ if (isCompiled(mode, input->hasLatin1Chars(), force) || canStringMatch)
return true;
- return compile(cx, input, mode);
+ return compile(cx, input, mode, force);
}
RegExpRunStatus
RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start,
MatchPairs *matches)
{
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
CompilationMode mode = matches ? Normal : MatchOnly;
/* Compile the code at point-of-use. */
- if (!compileIfNecessary(cx, input, mode))
+ if (!compileIfNecessary(cx, input, mode, DontForceByteCode))
return RegExpRunStatus_Error;
/*
* Ensure sufficient memory for output vector.
* No need to initialize it. The RegExp engine fills them in on a match.
*/
if (matches && !matches->allocOrExpandArray(pairCount()))
return RegExpRunStatus_Error;
@@ -586,86 +592,93 @@ RegExpShared::execute(JSContext *cx, Han
(*matches)[0].start = res;
(*matches)[0].limit = res + source->length();
matches->checkAgainst(origLength);
}
return RegExpRunStatus_Success;
}
- if (uint8_t *byteCode = compilation(mode, input->hasLatin1Chars()).byteCode) {
- AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
-
- AutoStableStringChars inputChars(cx);
- if (!inputChars.init(cx, input))
- return RegExpRunStatus_Error;
+ do {
+ jit::JitCode *code = compilation(mode, input->hasLatin1Chars()).jitCode;
+ if (!code)
+ break;
RegExpRunStatus result;
- if (inputChars.isLatin1()) {
- const Latin1Char *chars = inputChars.latin1Range().start().get() + charsOffset;
- result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches);
- } else {
- const char16_t *chars = inputChars.twoByteRange().start().get() + charsOffset;
- result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches);
- }
-
- if (result == RegExpRunStatus_Success && matches) {
- matches->displace(displacement);
- matches->checkAgainst(origLength);
- }
- return result;
- }
-
- while (true) {
- RegExpRunStatus result;
{
AutoTraceLog logJIT(logger, TraceLogger::IrregexpExecute);
AutoCheckCannotGC nogc;
- jit::JitCode *code = compilation(mode, input->hasLatin1Chars()).jitCode;
if (input->hasLatin1Chars()) {
const Latin1Char *chars = input->latin1Chars(nogc) + charsOffset;
result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
} else {
const char16_t *chars = input->twoByteChars(nogc) + charsOffset;
result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
}
}
if (result == RegExpRunStatus_Error) {
// The RegExp engine might exit with an exception if an interrupt
- // was requested. Check this case and retry until a clean result is
- // obtained.
+ // was requested. If this happens, break out and retry the regexp
+ // in the bytecode interpreter, which can execute while tolerating
+ // future interrupts. Otherwise, if we keep getting interrupted we
+ // will never finish executing the regexp.
bool interrupted;
{
JSRuntime::AutoLockForInterrupt lock(cx->runtime());
interrupted = cx->runtime()->interrupt;
}
if (interrupted) {
if (!InvokeInterruptCallback(cx))
return RegExpRunStatus_Error;
- continue;
+ break;
}
js_ReportOverRecursed(cx);
return RegExpRunStatus_Error;
}
if (result == RegExpRunStatus_Success_NotFound)
return RegExpRunStatus_Success_NotFound;
MOZ_ASSERT(result == RegExpRunStatus_Success);
- break;
+
+ if (matches) {
+ matches->displace(displacement);
+ matches->checkAgainst(origLength);
+ }
+ return RegExpRunStatus_Success;
+ } while (false);
+
+ // Compile bytecode for the RegExp if necessary.
+ if (!compileIfNecessary(cx, input, mode, ForceByteCode))
+ return RegExpRunStatus_Error;
+
+ uint8_t *byteCode = compilation(mode, input->hasLatin1Chars()).byteCode;
+ AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
+
+ AutoStableStringChars inputChars(cx);
+ if (!inputChars.init(cx, input))
+ return RegExpRunStatus_Error;
+
+ RegExpRunStatus result;
+ if (inputChars.isLatin1()) {
+ const Latin1Char *chars = inputChars.latin1Range().start().get() + charsOffset;
+ result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches);
+ } else {
+ const char16_t *chars = inputChars.twoByteRange().start().get() + charsOffset;
+ result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches);
}
- if (matches) {
+ if (result == RegExpRunStatus_Success && matches) {
matches->displace(displacement);
matches->checkAgainst(origLength);
}
- return RegExpRunStatus_Success;
+ return result;
}
size_t
RegExpShared::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
{
size_t n = mallocSizeOf(this);
for (size_t i = 0; i < ArrayLength(compilationArray); i++) {
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -101,31 +101,38 @@ CloneRegExpObject(JSContext *cx, JSObjec
class RegExpShared
{
public:
enum CompilationMode {
Normal,
MatchOnly
};
+ enum ForceByteCodeEnum {
+ DontForceByteCode,
+ ForceByteCode
+ };
+
private:
friend class RegExpCompartment;
friend class RegExpStatics;
typedef frontend::TokenStream TokenStream;
struct RegExpCompilation
{
HeapPtrJitCode jitCode;
uint8_t *byteCode;
RegExpCompilation() : byteCode(nullptr) {}
~RegExpCompilation() { js_free(byteCode); }
- bool compiled() const { return jitCode || byteCode; }
+ bool compiled(ForceByteCodeEnum force = DontForceByteCode) const {
+ return byteCode || (force == DontForceByteCode && jitCode);
+ }
};
/* Source to the RegExp, for lazy compilation. */
HeapPtrAtom source;
RegExpFlag flags;
size_t parenCount;
bool canStringMatch;
@@ -140,20 +147,23 @@ class RegExpShared
}
MOZ_CRASH();
}
// Tables referenced by JIT code.
Vector<uint8_t *, 0, SystemAllocPolicy> tables;
/* Internal functions. */
- bool compile(JSContext *cx, HandleLinearString input, CompilationMode mode);
- bool compile(JSContext *cx, HandleAtom pattern, HandleLinearString input, CompilationMode mode);
+ bool compile(JSContext *cx, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force);
+ bool compile(JSContext *cx, HandleAtom pattern, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force);
- bool compileIfNecessary(JSContext *cx, HandleLinearString input, CompilationMode mode);
+ bool compileIfNecessary(JSContext *cx, HandleLinearString input,
+ CompilationMode mode, ForceByteCodeEnum force);
const RegExpCompilation &compilation(CompilationMode mode, bool latin1) const {
return compilationArray[CompilationIndex(mode, latin1)];
}
RegExpCompilation &compilation(CompilationMode mode, bool latin1) {
return compilationArray[CompilationIndex(mode, latin1)];
}
@@ -184,18 +194,19 @@ class RegExpShared
JSAtom *getSource() const { return source; }
RegExpFlag getFlags() const { return flags; }
bool ignoreCase() const { return flags & IgnoreCaseFlag; }
bool global() const { return flags & GlobalFlag; }
bool multiline() const { return flags & MultilineFlag; }
bool sticky() const { return flags & StickyFlag; }
- bool isCompiled(CompilationMode mode, bool latin1) const {
- return compilation(mode, latin1).compiled();
+ bool isCompiled(CompilationMode mode, bool latin1,
+ ForceByteCodeEnum force = DontForceByteCode) const {
+ return compilation(mode, latin1).compiled(force);
}
bool isCompiled() const {
return isCompiled(Normal, true) || isCompiled(Normal, false)
|| isCompiled(MatchOnly, true) || isCompiled(MatchOnly, false);
}
void trace(JSTracer *trc);
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -346,16 +346,25 @@ FrameIter::unaliasedForEachActual(JSCont
break;
case INTERP:
interpFrame()->unaliasedForEachActual(op);
return;
case JIT:
if (data_.jitFrames_.isIonJS()) {
jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, recover);
+ } else if (data_.jitFrames_.isBailoutJS()) {
+ // :TODO: (Bug 1070962) If we are introspecting the frame which is
+ // being bailed, then we might be in the middle of recovering
+ // instructions. Stacking computeInstructionResults implies that we
+ // might be recovering result twice. In the mean time, to avoid
+ // that, we just return Undefined values for instruction results
+ // which are not yet recovered.
+ jit::MaybeReadFallback fallback;
+ ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, fallback);
} else {
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
data_.jitFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals);
}
return;
}
MOZ_CRASH("Unexpected state");
}
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -623,17 +623,17 @@ FrameIter::Data::Data(ThreadSafeContext
ContextOption contextOption, JSPrincipals *principals)
: cx_(cx),
savedOption_(savedOption),
contextOption_(contextOption),
principals_(principals),
pc_(nullptr),
interpFrames_(nullptr),
activations_(cx->perThreadData),
- jitFrames_((uint8_t *)nullptr, SequentialExecution),
+ jitFrames_(),
ionInlineFrameNo_(0),
asmJSFrames_()
{
}
FrameIter::Data::Data(const FrameIter::Data &other)
: cx_(other.cx_),
savedOption_(other.savedOption_),
@@ -674,50 +674,50 @@ FrameIter::FrameIter(JSContext *cx, Cont
ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
{
settleOnActivation();
}
FrameIter::FrameIter(const FrameIter &other)
: data_(other.data_),
ionInlineFrames_(other.data_.cx_,
- data_.jitFrames_.isIonJS() ? &other.ionInlineFrames_ : nullptr)
+ data_.jitFrames_.isIonScripted() ? &other.ionInlineFrames_ : nullptr)
{
}
FrameIter::FrameIter(const Data &data)
: data_(data),
- ionInlineFrames_(data.cx_, data_.jitFrames_.isIonJS() ? &data_.jitFrames_ : nullptr)
+ ionInlineFrames_(data.cx_, data_.jitFrames_.isIonScripted() ? &data_.jitFrames_ : nullptr)
{
MOZ_ASSERT(data.cx_);
- if (data_.jitFrames_.isIonJS()) {
+ if (data_.jitFrames_.isIonScripted()) {
while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
++ionInlineFrames_;
}
}
void
FrameIter::nextJitFrame()
{
- if (data_.jitFrames_.isIonJS()) {
+ if (data_.jitFrames_.isIonScripted()) {
ionInlineFrames_.resetOn(&data_.jitFrames_);
data_.pc_ = ionInlineFrames_.pc();
} else {
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
}
}
void
FrameIter::popJitFrame()
{
MOZ_ASSERT(data_.state_ == JIT);
- if (data_.jitFrames_.isIonJS() && ionInlineFrames_.more()) {
+ if (data_.jitFrames_.isIonScripted() && ionInlineFrames_.more()) {
++ionInlineFrames_;
data_.pc_ = ionInlineFrames_.pc();
return;
}
++data_.jitFrames_;
while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted())
++data_.jitFrames_;
@@ -784,17 +784,17 @@ FrameIter::operator++()
return *this;
}
FrameIter::Data *
FrameIter::copyData() const
{
Data *data = data_.cx_->new_<Data>(data_);
MOZ_ASSERT(data_.state_ != ASMJS);
- if (data && data_.jitFrames_.isIonJS())
+ if (data && data_.jitFrames_.isIonScripted())
data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
return data;
}
AbstractFramePtr
FrameIter::copyDataAsAbstractFramePtr() const
{
AbstractFramePtr frame;
@@ -992,17 +992,17 @@ FrameIter::mutedErrors() const
bool
FrameIter::isConstructing() const
{
switch (data_.state_) {
case DONE:
case ASMJS:
break;
case JIT:
- if (data_.jitFrames_.isIonJS())
+ if (data_.jitFrames_.isIonScripted())
return ionInlineFrames_.isConstructing();
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
return data_.jitFrames_.isConstructing();
case INTERP:
return interpFrame()->isConstructing();
}
MOZ_CRASH("Unexpected state");
@@ -1021,17 +1021,17 @@ FrameIter::hasUsableAbstractFramePtr() c
switch (data_.state_) {
case DONE:
case ASMJS:
return false;
case JIT:
if (data_.jitFrames_.isBaselineJS())
return true;
- MOZ_ASSERT(data_.jitFrames_.isIonJS());
+ MOZ_ASSERT(data_.jitFrames_.isIonScripted());
return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
ionInlineFrames_.frameNo());
break;
case INTERP:
return true;
}
MOZ_CRASH("Unexpected state");
}
@@ -1043,17 +1043,17 @@ FrameIter::abstractFramePtr() const
switch (data_.state_) {
case DONE:
case ASMJS:
break;
case JIT: {
if (data_.jitFrames_.isBaselineJS())
return data_.jitFrames_.baselineFrame();
- MOZ_ASSERT(data_.jitFrames_.isIonJS());
+ MOZ_ASSERT(data_.jitFrames_.isIonScripted());
return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
ionInlineFrames_.frameNo());
break;
}
case INTERP:
MOZ_ASSERT(interpFrame());
return AbstractFramePtr(interpFrame());
}
@@ -1115,17 +1115,17 @@ FrameIter::callee() const
case ASMJS:
break;
case INTERP:
MOZ_ASSERT(isFunctionFrame());
return &interpFrame()->callee();
case JIT:
if (data_.jitFrames_.isBaselineJS())
return data_.jitFrames_.callee();
- MOZ_ASSERT(data_.jitFrames_.isIonJS());
+ MOZ_ASSERT(data_.jitFrames_.isIonScripted());
return ionInlineFrames_.callee();
}
MOZ_CRASH("Unexpected state");
}
Value
FrameIter::calleev() const
{
@@ -1148,17 +1148,17 @@ FrameIter::numActualArgs() const
switch (data_.state_) {
case DONE:
case ASMJS:
break;
case INTERP:
MOZ_ASSERT(isFunctionFrame());
return interpFrame()->numActualArgs();
case JIT:
- if (data_.jitFrames_.isIonJS())
+ if (data_.jitFrames_.isIonScripted())
return ionInlineFrames_.numActualArgs();
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
return data_.jitFrames_.numActualArgs();
}
MOZ_CRASH("Unexpected state");
}
@@ -1177,17 +1177,17 @@ FrameIter::unaliasedActual(unsigned i, M
JSObject *
FrameIter::scopeChain() const
{
switch (data_.state_) {
case DONE:
case ASMJS:
break;
case JIT:
- if (data_.jitFrames_.isIonJS())
+ if (data_.jitFrames_.isIonScripted())
return ionInlineFrames_.scopeChain();
return data_.jitFrames_.baselineFrame()->scopeChain();
case INTERP:
return interpFrame()->scopeChain();
}
MOZ_CRASH("Unexpected state");
}
@@ -1232,17 +1232,17 @@ FrameIter::computedThisValue() const
Value
FrameIter::thisv(JSContext *cx)
{
switch (data_.state_) {
case DONE:
case ASMJS:
break;
case JIT:
- if (data_.jitFrames_.isIonJS()) {
+ if (data_.jitFrames_.isIonScripted()) {
jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
return ionInlineFrames_.thisValue(recover);
}
return data_.jitFrames_.baselineFrame()->thisValue();
case INTERP:
return interpFrame()->thisValue();
}
MOZ_CRASH("Unexpected state");
@@ -1288,17 +1288,17 @@ FrameIter::setReturnValue(const Value &v
size_t
FrameIter::numFrameSlots() const
{
switch (data_.state_) {
case DONE:
case ASMJS:
break;
case JIT: {
- if (data_.jitFrames_.isIonJS()) {
+ if (data_.jitFrames_.isIonScripted()) {
return ionInlineFrames_.snapshotIterator().numAllocations() -
ionInlineFrames_.script()->nfixed();
}
jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame();
return frame->numValueSlots() - data_.jitFrames_.script()->nfixed();
}
case INTERP:
MOZ_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
@@ -1310,17 +1310,17 @@ FrameIter::numFrameSlots() const
Value
FrameIter::frameSlotValue(size_t index) const
{
switch (data_.state_) {
case DONE:
case ASMJS:
break;
case JIT:
- if (data_.jitFrames_.isIonJS()) {
+ if (data_.jitFrames_.isIonScripted()) {
jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
index += ionInlineFrames_.script()->nfixed();
return si.maybeReadAllocByIndex(index);
}
index += data_.jitFrames_.script()->nfixed();
return *data_.jitFrames_.baselineFrame()->valueSlot(index);
case INTERP:
@@ -1399,52 +1399,73 @@ js::CheckLocalUnaliased(MaybeCheckAliasi
}
}
#endif
jit::JitActivation::JitActivation(JSContext *cx, bool active)
: Activation(cx, Jit),
active_(active),
rematerializedFrames_(nullptr),
- ionRecovery_(cx)
+ ionRecovery_(cx),
+ bailoutData_(nullptr)
{
if (active) {
prevJitTop_ = cx->mainThread().jitTop;
prevJitJSContext_ = cx->mainThread().jitJSContext;
cx->mainThread().jitJSContext = cx;
} else {
prevJitTop_ = nullptr;
prevJitJSContext_ = nullptr;
}
}
jit::JitActivation::JitActivation(ForkJoinContext *cx)
: Activation(cx, Jit),
active_(true),
rematerializedFrames_(nullptr),
- ionRecovery_(cx)
+ ionRecovery_(cx),
+ bailoutData_(nullptr)
{
prevJitTop_ = cx->perThreadData->jitTop;
prevJitJSContext_ = cx->perThreadData->jitJSContext;
cx->perThreadData->jitJSContext = nullptr;
}
jit::JitActivation::~JitActivation()
{
if (active_) {
cx_->perThreadData->jitTop = prevJitTop_;
cx_->perThreadData->jitJSContext = prevJitJSContext_;
}
- clearRematerializedFrames();
// All reocvered value are taken from activation during the bailout.
MOZ_ASSERT(ionRecovery_.empty());
+
+ // The BailoutFrameInfo should have unregistered itself from the
+ // JitActivations.
+ MOZ_ASSERT(!bailoutData_);
+
+ clearRematerializedFrames();
js_delete(rematerializedFrames_);
}
+void
+jit::JitActivation::setBailoutData(jit::BailoutFrameInfo *bailoutData)
+{
+ MOZ_ASSERT(!bailoutData_);
+ bailoutData_ = bailoutData;
+}
+
+void
+jit::JitActivation::cleanBailoutData()
+{
+ MOZ_ASSERT(bailoutData_);
+ bailoutData_ = nullptr;
+}
+
// setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
// changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
// and disable activation instruction sequences.
void
jit::JitActivation::setActive(JSContext *cx, bool active)
{
// Only allowed to deactivate/activate if activation is top.
// (Not tested and will probably fail in other situations.)
@@ -1481,24 +1502,23 @@ jit::JitActivation::clearRematerializedF
return;
for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) {
RematerializedFrame::FreeInVector(e.front().value());
e.removeFront();
}
}
-template <class T>
jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const T &iter, size_t inlineDepth)
+jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter, size_t inlineDepth)
{
// Only allow rematerializing from the same thread.
MOZ_ASSERT(cx->perThreadData == cx_->perThreadData);
MOZ_ASSERT(iter.activation() == this);
- MOZ_ASSERT(iter.isIonJS());
+ MOZ_ASSERT(iter.isIonScripted());
if (!rematerializedFrames_) {
rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
if (!rematerializedFrames_ || !rematerializedFrames_->init()) {
rematerializedFrames_ = nullptr;
return nullptr;
}
}
@@ -1518,25 +1538,16 @@ jit::JitActivation::getRematerializedFra
InlineFrameIterator inlineIter(cx, &iter);
if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, p->value()))
return nullptr;
}
return p->value()[inlineDepth];
}
-template jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame<jit::JitFrameIterator>(ThreadSafeContext *cx,
- const jit::JitFrameIterator &iter,
- size_t inlineDepth);
-template jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame<jit::IonBailoutIterator>(ThreadSafeContext *cx,
- const jit::IonBailoutIterator &iter,
- size_t inlineDepth);
-
jit::RematerializedFrame *
jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth)
{
if (!rematerializedFrames_)
return nullptr;
if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top))
return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
return nullptr;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1296,16 +1296,18 @@ class ActivationIterator
}
bool done() const {
return activation_ == nullptr;
}
};
namespace jit {
+class BailoutFrameInfo;
+
// A JitActivation is used for frames running in Baseline or Ion.
class JitActivation : public Activation
{
uint8_t *prevJitTop_;
JSContext *prevJitJSContext_;
bool active_;
// Rematerialized Ion frames which has info copied out of snapshots. Maps
@@ -1322,16 +1324,23 @@ class JitActivation : public Activation
//
// RInstructionResults are appended into this vector when Snapshot values
// have to be read, or when the evaluation has to run before some mutating
// code. Each RInstructionResults belongs to one frame which has to bailout
// as soon as we get back to it.
typedef Vector<RInstructionResults, 1> IonRecoveryMap;
IonRecoveryMap ionRecovery_;
+ // If we are bailing out from Ion, then this field should be a non-null
+ // pointer which references the BailoutFrameInfo used to walk the inner
+ // frames. This field is used for all newly constructed JitFrameIterators to
+ // read the innermost frame information from this bailout data instead of
+ // reading it from the stack.
+ BailoutFrameInfo *bailoutData_;
+
void clearRematerializedFrames();
#ifdef CHECK_OSIPOINT_REGISTERS
protected:
// Used to verify that live registers don't change between a VM call and
// the OsiPoint that follows it. Protected to silence Clang warning.
uint32_t checkRegs_;
RegisterDump regs_;
@@ -1377,21 +1386,18 @@ class JitActivation : public Activation
}
#endif
// Look up a rematerialized frame keyed by the fp, rematerializing the
// frame if one doesn't already exist. A frame can only be rematerialized
// if an IonFrameIterator pointing to the nearest uninlined frame can be
// provided, as values need to be read out of snapshots.
//
- // T is either JitFrameIterator or IonBailoutIterator.
- //
// The inlineDepth must be within bounds of the frame pointed to by iter.
- template <class T>
- RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const T &iter,
+ RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter,
size_t inlineDepth = 0);
// Look up a rematerialized frame by the fp. If inlineDepth is out of
// bounds of what has been rematerialized, nullptr is returned.
RematerializedFrame *lookupRematerializedFrame(uint8_t *top, size_t inlineDepth = 0);
bool hasRematerializedFrame(uint8_t *top, size_t inlineDepth = 0) {
return !!lookupRematerializedFrame(top, inlineDepth);
@@ -1410,16 +1416,25 @@ class JitActivation : public Activation
RInstructionResults *maybeIonFrameRecovery(IonJSFrameLayout *fp);
// If an Ion frame recovery exists for the |fp| frame exists on the
// activation, then move its content to the |results| argument, and remove
// it from the activation.
void maybeTakeIonFrameRecovery(IonJSFrameLayout *fp, RInstructionResults *results);
void markIonRecovery(JSTracer *trc);
+
+ // Return the bailout information if it is registered.
+ const BailoutFrameInfo *bailoutData() const { return bailoutData_; }
+
+ // Register the bailout data when it is constructed.
+ void setBailoutData(BailoutFrameInfo *bailoutData);
+
+ // Unregister the bailout data when the frame is reconstructed.
+ void cleanBailoutData();
};
// A filtering of the ActivationIterator to only stop at JitActivations.
class JitActivationIterator : public ActivationIterator
{
void settle() {
while (!done() && !activation_->isJit())
ActivationIterator::operator++();
--- a/layout/base/TouchCaret.cpp
+++ b/layout/base/TouchCaret.cpp
@@ -25,16 +25,17 @@
#include "mozilla/Preferences.h"
#include "mozilla/BasicEvents.h"
#include "nsIDOMWindow.h"
#include "nsQueryContentEventResult.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsView.h"
#include "nsDOMTokenList.h"
#include "nsCaret.h"
+#include "mozilla/dom/CustomEvent.h"
using namespace mozilla;
// To enable all the TOUCHCARET_LOG print statements, change the 0 to 1 in the
// following #define.
#define ENABLE_TOUCHCARET_LOG 0
#if ENABLE_TOUCHCARET_LOG
@@ -53,17 +54,18 @@ NS_IMPL_ISUPPORTS(TouchCaret, nsISelecti
/*static*/ int32_t TouchCaret::sTouchCaretInflateSize = 0;
/*static*/ int32_t TouchCaret::sTouchCaretExpirationTime = 0;
TouchCaret::TouchCaret(nsIPresShell* aPresShell)
: mState(TOUCHCARET_NONE),
mActiveTouchId(-1),
mCaretCenterToDownPointOffsetY(0),
- mVisible(false)
+ mVisible(false),
+ mIsValidTap(false)
{
TOUCHCARET_LOG("Constructor, PresShell=%p", aPresShell);
MOZ_ASSERT(NS_IsMainThread());
static bool addedTouchCaretPref = false;
if (!addedTouchCaretPref) {
Preferences::AddIntVarCache(&sTouchCaretInflateSize,
"touchcaret.inflatesize.threshold");
@@ -596,16 +598,17 @@ TouchCaret::HandleMouseMoveEvent(WidgetM
case TOUCHCARET_MOUSEDRAG_ACTIVE:
{
nsPoint movePoint = GetEventPosition(aEvent);
movePoint.y += mCaretCenterToDownPointOffsetY;
nsRect contentBoundary = GetContentBoundary();
movePoint = contentBoundary.ClampPoint(movePoint);
MoveCaret(movePoint);
+ mIsValidTap = false;
status = nsEventStatus_eConsumeNoDefault;
}
break;
case TOUCHCARET_TOUCHDRAG_ACTIVE:
case TOUCHCARET_TOUCHDRAG_INACTIVE:
// Consume mouse event in touch sequence.
status = nsEventStatus_eConsumeNoDefault;
@@ -633,16 +636,17 @@ TouchCaret::HandleTouchMoveEvent(WidgetT
case TOUCHCARET_TOUCHDRAG_ACTIVE:
{
nsPoint movePoint = GetEventPosition(aEvent, mActiveTouchId);
movePoint.y += mCaretCenterToDownPointOffsetY;
nsRect contentBoundary = GetContentBoundary();
movePoint = contentBoundary.ClampPoint(movePoint);
MoveCaret(movePoint);
+ mIsValidTap = false;
status = nsEventStatus_eConsumeNoDefault;
}
break;
case TOUCHCARET_TOUCHDRAG_INACTIVE:
// Consume NS_TOUCH_MOVE event in TOUCHCARET_TOUCHDRAG_INACTIVE state.
status = nsEventStatus_eConsumeNoDefault;
break;
@@ -844,16 +848,45 @@ TouchCaret::HandleTouchDownEvent(WidgetT
mTouchesId.AppendElement(aEvent->touches[i]->mIdentifier);
}
}
return status;
}
void
+TouchCaret::DispatchTapEvent()
+{
+ nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
+ if (!presShell) {
+ return;
+ }
+
+ nsCOMPtr<nsIDocument> doc = presShell->GetDocument();
+ if (!doc) {
+ return;
+ }
+
+ ErrorResult res;
+ nsRefPtr<dom::Event> domEvent =
+ doc->CreateEvent(NS_LITERAL_STRING("CustomEvent"), res);
+ if (res.Failed()) {
+ return;
+ }
+
+ dom::CustomEvent* customEvent = static_cast<dom::CustomEvent*>(domEvent.get());
+ customEvent->InitCustomEvent(NS_LITERAL_STRING("touchcarettap"),
+ true, false, nullptr);
+ customEvent->SetTrusted(true);
+ customEvent->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+ bool ret;
+ doc->DispatchEvent(domEvent, &ret);
+}
+
+void
TouchCaret::SetState(TouchCaretState aState)
{
TOUCHCARET_LOG("state changed from %d to %d", mState, aState);
if (mState == TOUCHCARET_NONE) {
MOZ_ASSERT(aState != TOUCHCARET_TOUCHDRAG_INACTIVE,
"mState: NONE => TOUCHDRAG_INACTIVE isn't allowed!");
}
@@ -874,10 +907,17 @@ TouchCaret::SetState(TouchCaretState aSt
"TOUCHDRAG_INACTIVE allowed next state: NONE!");
}
mState = aState;
if (mState == TOUCHCARET_NONE) {
mActiveTouchId = -1;
mCaretCenterToDownPointOffsetY = 0;
+ if (mIsValidTap) {
+ DispatchTapEvent();
+ mIsValidTap = false;
+ }
+ } else if (mState == TOUCHCARET_TOUCHDRAG_ACTIVE ||
+ mState == TOUCHCARET_MOUSEDRAG_ACTIVE) {
+ mIsValidTap = true;
}
}
--- a/layout/base/TouchCaret.h
+++ b/layout/base/TouchCaret.h
@@ -205,16 +205,21 @@ private:
};
/**
* Do actual state transition and reset substates.
*/
void SetState(TouchCaretState aState);
/**
+ * Dispatch touch caret tap event to chrome.
+ */
+ void DispatchTapEvent();
+
+ /**
* Current state we're dealing with.
*/
TouchCaretState mState;
/**
* Array containing all active touch IDs. When a touch happens, it gets added
* to this array, even if we choose not to handle it. When it ends, we remove
* it. We need to maintain this array in order to detect the end of the
@@ -244,16 +249,18 @@ private:
{
return sTouchCaretExpirationTime;
}
nsWeakPtr mPresShell;
// Touch caret visibility
bool mVisible;
+ // Use for detecting single tap on touch caret.
+ bool mIsValidTap;
// Touch caret timer
nsCOMPtr<nsITimer> mTouchCaretExpirationTimer;
// Preference
static int32_t sTouchCaretInflateSize;
static int32_t sTouchCaretExpirationTime;
// The auto scroll timer's interval in miliseconds.
--- a/layout/reftests/forms/input/range/reftest.list
+++ b/layout/reftests/forms/input/range/reftest.list
@@ -17,17 +17,17 @@
== value-prop.html 75pct-common-ref.html
== valueAsNumber-prop-unthemed.html 75pct-unthemed-common-ref.html
== valueAsNumber-prop.html 75pct-common-ref.html
fuzzy-if(B2G,1,1) == stepDown-unthemed.html 75pct-unthemed-common-ref.html
fuzzy-if(B2G,1,1) == stepDown.html 75pct-common-ref.html
== stepUp-unthemed.html 75pct-unthemed-common-ref.html
== stepUp.html 75pct-common-ref.html
fuzzy-if(B2G,1,1) == max-prop.html 100pct-common-ref.html
+== reset-value.html reset-value-ref.html
# 'direction' property:
== direction-unthemed-1.html direction-unthemed-1-ref.html
# ::-moz-range-progress pseudo-element:
fails-if(B2G||Android) == moz-range-progress-1.html moz-range-progress-1-ref.html
== moz-range-progress-2.html moz-range-progress-2-ref.html
== moz-range-progress-3.html moz-range-progress-3-ref.html
-
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/range/reset-value-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en-us">
+ <head>
+ <title>1080352</title>
+ </head>
+ <body>
+ <form id="form">
+ <input id='inputRange' type='range' step='10' min='0' max='50' value='20'><br>
+ <input id='inputNumber' type='number' step='10' min='0' max='500' value='30'><br>
+
+ <input type='reset'><br>
+ </form>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/range/reset-value.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en-us">
+ <head>
+ <title>1080352</title>
+ </head>
+ <body onload="inputRange.value=40;inputNumber.value=40; form.reset()">
+ <form id="form">
+ <input id='inputRange' type='range' step='10' min='0' max='50' value='20'><br>
+ <input id='inputNumber' type='number' step='10' min='0' max='500' value='30'><br>
+
+ <input type='reset'><br>
+ </form>
+ </body>
+</html>
--- a/netwerk/base/public/nsIEncodedChannel.idl
+++ b/netwerk/base/public/nsIEncodedChannel.idl
@@ -8,17 +8,17 @@
interface nsIUTF8StringEnumerator;
interface nsIStreamListener;
interface nsISupports;
/**
* A channel interface which allows special handling of encoded content
*/
-[scriptable, uuid(30d7ec3a-f376-4652-9276-3092ec57abb6)]
+[scriptable, uuid(29c29ce6-8ce4-45e6-8d60-36c8fa3e255b)]
interface nsIEncodedChannel : nsISupports
{
/**
* This attribute holds the MIME types corresponding to the content
* encodings on the channel. The enumerator returns nsISupportsCString
* objects. The first one corresponds to the outermost encoding on the
* channel and then we work our way inward. "identity" is skipped and not
* represented on the list. Unknown encodings make the enumeration stop.
--- a/security/manager/ssl/public/nsIX509CertList.idl
+++ b/security/manager/ssl/public/nsIX509CertList.idl
@@ -2,17 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsISimpleEnumerator;
interface nsIX509Cert;
-[scriptable, uuid(a539759b-e22d-462f-94ea-2915b11b33e8)]
+[scriptable, uuid(ae74cda5-cd2f-473f-96f5-f0b7fff62c68)]
interface nsIX509CertList : nsISupports {
void addCert(in nsIX509Cert cert);
void deleteCert(in nsIX509Cert cert);
nsISimpleEnumerator getEnumerator();
/* getRawCertList MUST be called only from functions where
* the nssShutdownPreventionLock has been adquired.
*/
--- a/testing/marionette/client/marionette/marionette.py
+++ b/testing/marionette/client/marionette/marionette.py
@@ -810,17 +810,17 @@ class Marionette(object):
"""Create a new Marionette session.
This method must be called before performing any other action.
:params desired_capabilities: An optional dict of desired
capabilities. This is currently ignored.
:returns: A dict of the capabilities offered."""
- self.session = self._send_message('newSession', 'value')
+ self.session = self._send_message('newSession', 'value', capabilities=desired_capabilities)
self.b2g = 'b2g' in self.session
return self.session
@property
def test_name(self):
return self._test_name
@test_name.setter
--- a/testing/marionette/client/marionette/tests/unit/test_capabilities.py
+++ b/testing/marionette/client/marionette/tests/unit/test_capabilities.py
@@ -47,8 +47,15 @@ class TestCapabilities(MarionetteTestCas
self.assertIn("XULappId", self.caps)
self.assertIn("appBuildId", self.caps)
self.assertIn("device", self.caps)
self.assertIn("version", self.caps)
self.assertEqual(self.caps["XULappId"], self.appinfo["ID"])
self.assertEqual(self.caps["appBuildId"], self.appinfo["appBuildID"])
self.assertEqual(self.caps["version"], self.appinfo["version"])
+
+ def test_we_can_pass_in_capabilities_on_session_start(self):
+ self.marionette.delete_session()
+ capabilities = {"somethingAwesome": "cake"}
+ self.marionette.start_session(capabilities)
+ caps = self.marionette.session_capabilities
+ self.assertIn("somethingAwesome", caps)
\ No newline at end of file
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -137,16 +137,40 @@ function MarionetteServerConnection(aPre
this.curFrame = null; // chrome iframe that currently has focus
this.mainContentFrameId = null;
this.importedScripts = FileUtils.getFile('TmpD', ['marionetteChromeScripts']);
this.importedScriptHashes = {"chrome" : [], "content": []};
this.currentFrameElement = null;
this.testName = null;
this.mozBrowserClose = null;
this.oopFrameId = null; // frame ID of current remote frame, used for mozbrowserclose events
+ this.sessionCapabilities = {
+ // Mandated capabilities
+ "browserName": appName,
+ "browserVersion": Services.appinfo.version,
+ "platformName": Services.appinfo.OS.toUpperCase(),
+ "platformVersion": Services.appinfo.platformVersion,
+
+ // Supported features
+ "handlesAlerts": false,
+ "nativeEvents": false,
+ "rotatable": appName == "B2G",
+ "secureSsl": false,
+ "takesElementScreenshot": true,
+ "takesScreenshot": true,
+
+ // Selenium 2 compat
+ "platform": Services.appinfo.OS.toUpperCase(),
+
+ // Proprietary extensions
+ "XULappId" : Services.appinfo.ID,
+ "appBuildId" : Services.appinfo.appBuildID,
+ "device": qemu == "1" ? "qemu" : (!device ? "desktop" : device),
+ "version": Services.appinfo.version
+ };
}
MarionetteServerConnection.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
@@ -511,21 +535,25 @@ MarionetteServerConnection.prototype = {
*
* In a desktop environment, this opens a new browser with
* "about:blank" which subsequent commands will be sent to.
*
* This will send a hash map of supported capabilities to the client
* as part of the Marionette:register IPC command in the
* receiveMessage callback when a new browser is created.
*/
- newSession: function MDA_newSession() {
+ newSession: function MDA_newSession(aRequest) {
+ logger.info("The newSession request is " + JSON.stringify(aRequest))
this.command_id = this.getCommandId();
this.newSessionCommandId = this.command_id;
this.scriptTimeout = 10000;
+ if (aRequest && aRequest.parameters) {
+ this.setSessionCapabilities(aRequest.parameters.capabilities);
+ }
function waitForWindow() {
let win = this.getCurrentWindow();
if (!win) {
// If the window isn't even created, just poll wait for it
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
checkTimer.initWithCallback(waitForWindow.bind(this), 100,
Ci.nsITimer.TYPE_ONE_SHOT);
@@ -574,51 +602,48 @@ MarionetteServerConnection.prototype = {
*
* The return value is an immutable map of string keys
* ("capabilities") to values, which may be of types boolean,
* numerical or string.
*/
getSessionCapabilities: function MDA_getSessionCapabilities() {
this.command_id = this.getCommandId();
- let isB2G = appName == "B2G";
- let platformName = Services.appinfo.OS.toUpperCase();
-
- let caps = {
- // Mandated capabilities
- "browserName": appName,
- "browserVersion": Services.appinfo.version,
- "platformName": platformName,
- "platformVersion": Services.appinfo.platformVersion,
-
- // Supported features
- "handlesAlerts": false,
- "nativeEvents": false,
- "rotatable": isB2G,
- "secureSsl": false,
- "takesElementScreenshot": true,
- "takesScreenshot": true,
-
- // Selenium 2 compat
- "platform": platformName,
-
- // Proprietary extensions
- "XULappId" : Services.appinfo.ID,
- "appBuildId" : Services.appinfo.appBuildID,
- "device": qemu == "1" ? "qemu" : (!device ? "desktop" : device),
- "version": Services.appinfo.version
- };
-
// eideticker (bug 965297) and mochitest (bug 965304)
// compatibility. They only check for the presence of this
// property and should so not be in caps if not on a B2G device.
- if (isB2G)
- caps.b2g = true;
+ if (appName == "B2G")
+ this.sessionCapabilities.b2g = true;
+
+ this.sendResponse(this.sessionCapabilities, this.command_id);
+ },
- this.sendResponse(caps, this.command_id);
+ /**
+ * Update the sessionCapabilities object with the keys that have been
+ * passed in when a new session is created
+ * This part of the WebDriver spec is currently in flux see
+ * http://lists.w3.org/Archives/Public/public-browser-tools-testing/2014OctDec/0000.html
+ *
+ * This is not a public API, only available when a new Session is created
+ *
+ * @param Object capabilities holds all the keys for capabilities
+ *
+ */
+ setSessionCapabilities: function MDA_setSessionCapabilities (capabilities) {
+ this.command_id = this.getCommandId();
+ var tempCapabilities = {};
+ for (var caps in this.sessionCapabilities) {
+ tempCapabilities[caps] = this.sessionCapabilities[caps];
+ }
+
+ for (var caps in capabilities) {
+ tempCapabilities[caps] = capabilities[caps];
+ }
+
+ this.sessionCapabilities = tempCapabilities;
},
/**
* Log message. Accepts user defined log-level.
*
* @param object aRequest
* 'value' member holds log message
* 'level' member hold log level
--- a/testing/mochitest/server.js
+++ b/testing/mochitest/server.js
@@ -105,16 +105,19 @@ if (this["nsHttpServer"]) {
// Impossible as the stop callback should have been called, but to be safe...
dumpn("TEST-UNEXPECTED-FAIL | failure to correctly shut down HTTP server");
quit(1);
}
var serverBasePath;
var displayResults = true;
+var gServerAddress;
+var SERVER_PORT;
+
//
// SERVER SETUP
//
function runServer()
{
serverBasePath = __LOCATION__.parent;
server = createMochitestServer(serverBasePath);
@@ -169,17 +172,17 @@ function runServer()
}
// If we're running outside of the test harness, there might
// not be a test profile directory present
if (serverAlive.exists()) {
serverAlive.append("server_alive.txt");
foStream.init(serverAlive,
0x02 | 0x08 | 0x20, 436, 0); // write, create, truncate
- data = "It's alive!";
+ var data = "It's alive!";
foStream.write(data, data.length);
foStream.close();
}
makeTags();
//
// The following is threading magic to spin an event loop -- this has to
@@ -436,17 +439,17 @@ function isTest(filename, pattern)
if (pattern)
return pattern.test(filename);
// File name is a URL style path to a test file, make sure that we check for
// tests that start with the appropriate prefix.
var testPrefix = typeof(_TEST_PREFIX) == "string" ? _TEST_PREFIX : "test_";
var testPattern = new RegExp("^" + testPrefix);
- pathPieces = filename.split('/');
+ var pathPieces = filename.split('/');
return testPattern.test(pathPieces[pathPieces.length - 1]) &&
filename.indexOf(".js") == -1 &&
filename.indexOf(".css") == -1 &&
!/\^headers\^$/.test(filename);
}
/**
@@ -489,17 +492,17 @@ function linksToListItems(links)
function linksToTableRows(links, recursionLevel)
{
var response = "";
for (var [link, value] in links) {
var classVal = (!isTest(link) && !(value instanceof Object))
? "non-test invisible"
: "";
- spacer = "padding-left: " + (10 * recursionLevel) + "px";
+ var spacer = "padding-left: " + (10 * recursionLevel) + "px";
if (value instanceof Object) {
response += TR({class: "dir", id: "tr-" + link },
TD({colspan: "3"}, " "),
TD({style: spacer},
A({href: link}, link)));
response += linksToTableRows(value, recursionLevel + 1);
} else {
--- a/testing/mozbase/mozdebug/mozdebug/mozdebug.py
+++ b/testing/mozbase/mozdebug/mozdebug/mozdebug.py
@@ -118,17 +118,17 @@ def get_debugger_info(debugger, debugger
['path', 'interactive', 'args', 'requiresEscapedArgs']
)
debugger_arguments = get_debugger_info('args', [])
# Extend the default arguments for the chosen debugger with the ones passed in, if any.
if debuggerArgs:
# Append the provided debugger arguments at the end of the arguments list.
- debugger_arguments.extend(debuggerArgs)
+ debugger_arguments += debuggerArgs.split()
# Override the default debugger interactive mode if needed.
debugger_interactive = get_debugger_info('interactive', False)
if debuggerInteractive:
debugger_interactive = debuggerInteractive
d = DebuggerInfo(
debuggerPath,
--- a/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
+++ b/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
@@ -169,19 +169,17 @@ class TestFileOperations(DeviceManagerAD
class TestOther(DeviceManagerADBTestCase):
def test_get_list_of_processes(self):
self.assertEquals(type(self.dm.getProcessList()), list)
def test_get_current_time(self):
self.assertEquals(type(self.dm.getCurrentTime()), int)
def test_get_info(self):
- self.assertEquals(self.dm.getInfo(), {})
- # Commented since it is too nosiy
- #self.assertEquals(self.dm.getInfo("all"), dict)
+ self.assertEquals(type(self.dm.getInfo()), dict)
def test_list_devices(self):
self.assertEquals(len(list(self.dm.devices())), 1)
def test_shell(self):
out = StringIO()
self.dm.shell(["echo", "$COMPANY", ";", "pwd"], out,
env={"COMPANY":"Mozilla"}, cwd="/", timeout=4, root=True)
--- a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
@@ -492,36 +492,33 @@ class DeviceManagerADB(DeviceManager):
def getCurrentTime(self):
timestr = str(self._runCmd(["shell", "date", "+%s"]).output[0])
if (not timestr or not timestr.isdigit()):
raise DMError("Unable to get current time using date (got: '%s')" % timestr)
return int(timestr)*1000
def getInfo(self, directive=None):
+ directive = directive or "all"
ret = {}
- if (directive == "id" or directive == "all"):
+ if directive == "id" or directive == "all":
ret["id"] = self._runCmd(["get-serialno"]).output[0]
- if (directive == "os" or directive == "all"):
- ret["os"] = self._runCmd(["shell", "getprop", "ro.build.display.id"]).output[0]
- if (directive == "uptime" or directive == "all"):
- utime = self._runCmd(["shell", "uptime"]).output[0]
+ if directive == "os" or directive == "all":
+ ret["os"] = self.shellCheckOutput(["getprop", "ro.build.display.id"])
+ if directive == "uptime" or directive == "all":
+ utime = self.shellCheckOutput(["uptime"])
if (not utime):
raise DMError("error getting uptime")
- utime = utime[9:]
- hours = utime[0:utime.find(":")]
- utime = utime[utime[1:].find(":") + 2:]
- minutes = utime[0:utime.find(":")]
- utime = utime[utime[1:].find(":") + 2:]
- seconds = utime[0:utime.find(",")]
- ret["uptime"] = ["0 days " + hours + " hours " + minutes + " minutes " + seconds + " seconds"]
- if (directive == "process" or directive == "all"):
- ret["process"] = self._runCmd(["shell", "ps"]).output
- if (directive == "systime" or directive == "all"):
- ret["systime"] = self._runCmd(["shell", "date"]).output[0]
+ m = re.match("up time: ((\d+) days, )*(\d{2}):(\d{2}):(\d{2})", utime)
+ ret["uptime"] = "%d days %d hours %d minutes %d seconds" % tuple(
+ [int(g or 0) for g in m.groups()[1:]])
+ if directive == "process" or directive == "all":
+ ret["process"] = self.shellCheckOutput(["ps"])
+ if directive == "systime" or directive == "all":
+ ret["systime"] = self.shellCheckOutput(["date"])
self._logger.info(ret)
return ret
def uninstallApp(self, appName, installPath=None):
status = self._runCmd(["uninstall", appName]).output[0].strip()
if status != 'Success':
raise DMError("uninstall failed for %s. Got: %s" % (appName, status))
--- a/testing/mozbase/mozdevice/mozdevice/dmcli.py
+++ b/testing/mozbase/mozdevice/mozdevice/dmcli.py
@@ -277,24 +277,21 @@ class DMCli(object):
buf = StringIO.StringIO()
self.dm.shell(args.command, buf, root=args.root)
print str(buf.getvalue()[0:-1]).rstrip()
def getinfo(self, args):
info = self.dm.getInfo(directive=args.directive)
for (infokey, infoitem) in sorted(info.iteritems()):
if infokey == "process":
- pass # skip process list: get that through ps
- elif not args.directive and not infoitem:
- print "%s:" % infokey.upper()
- elif not args.directive:
- for line in infoitem:
- print "%s: %s" % (infokey.upper(), line)
+ pass # skip process list: get that through ps
+ elif args.directive is None:
+ print "%s: %s" % (infokey.upper(), infoitem)
else:
- print "%s" % "\n".join(infoitem)
+ print infoitem
def logcat(self, args):
print ''.join(self.dm.getLogcat())
def clearlogcat(self, args):
self.dm.recordLogcat()
def reboot(self, args):
--- a/testing/specialpowers/content/MockFilePicker.jsm
+++ b/testing/specialpowers/content/MockFilePicker.jsm
@@ -84,17 +84,17 @@ this.MockFilePicker = {
registrar.unregisterFactory(newClassID, previousFactory);
registrar.registerFactory(oldClassID, "", CONTRACT_ID, oldFactory);
}
},
useAnyFile: function() {
var file = FileUtils.getDir("TmpD", [], false);
file.append("testfile");
- file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
+ file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
this.returnFiles = [file];
},
useBlobFile: function() {
var blob = new this.window.Blob([]);
var file = new this.window.File([blob], 'helloworld.txt', { type: 'plain/text' });
this.returnFiles = [file];
},