Merge m-c to fx-team

This commit is contained in:
Wes Kocher 2014-06-19 18:33:19 -07:00
commit b8d6b378bf
146 changed files with 3213 additions and 2386 deletions

View File

@ -19,13 +19,13 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3326b51017252e09ccdd715dec6c5e12a7d1ecfe"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
@ -98,7 +98,7 @@
<project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/>
<!-- Emulator specific things -->
<project name="android-development" path="development" remote="b2g" revision="9abf0ab68376afae3e1c7beefa3e9cbee2fde202"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="2fee3bbbfc236b883ef8507e27d88b17b203fe25"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="3cae7eee1f7f00ba1eb53c733a8779f345055c6e"/>
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>

View File

@ -17,10 +17,10 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>

View File

@ -19,13 +19,13 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3326b51017252e09ccdd715dec6c5e12a7d1ecfe"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
@ -98,7 +98,7 @@
<project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/>
<!-- Emulator specific things -->
<project name="android-development" path="development" remote="b2g" revision="9abf0ab68376afae3e1c7beefa3e9cbee2fde202"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="2fee3bbbfc236b883ef8507e27d88b17b203fe25"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="3cae7eee1f7f00ba1eb53c733a8779f345055c6e"/>
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>

View File

@ -17,10 +17,10 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "507ca54e4c4da9d3e1b1af92d7a306a71875d066",
"revision": "dcb55fbcaa9bd33e662a2c5e99cdb7e4c9d7ad51",
"repo_path": "/integration/gaia-central"
}

View File

@ -17,12 +17,12 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>

View File

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,10 +17,10 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

View File

@ -17,12 +17,12 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="135a13ea0ee333314b6a12cb19f18617308a3b46"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="ccd70903544486bea04e85d8a4aacf63f1de2a72"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="44b04243e31cd16f3baf54fcd4b5fecf9deb8b94"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="26e84ee3e9ef5df2ca28b16aa6719c6e77b5f24f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8ba14125aba912707f44761f194339e6e59701b7"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>

View File

@ -48,9 +48,16 @@ this.Translation = {
documentStateReceived: function(aBrowser, aData) {
if (aData.state == this.STATE_OFFER) {
if (this.supportedSourceLanguages.indexOf(aData.detectedLanguage) == -1 ||
aData.detectedLanguage == this.defaultTargetLanguage)
if (aData.detectedLanguage == this.defaultTargetLanguage) {
// Detected language is the same as the user's locale.
return;
}
if (this.supportedSourceLanguages.indexOf(aData.detectedLanguage) == -1) {
// Detected language is not part of the supported languages.
TranslationHealthReport.recordMissedTranslationOpportunity(aData.detectedLanguage);
return;
}
TranslationHealthReport.recordTranslationOpportunity(aData.detectedLanguage);
}
@ -258,6 +265,17 @@ let TranslationHealthReport = {
this._withProvider(provider => provider.recordTranslationOpportunity(language));
},
/**
* Record a missed translation opportunity in the health report.
* A missed opportunity is when the language detected is not part
* of the supported languages.
* @param language
* The language of the page.
*/
recordMissedTranslationOpportunity: function (language) {
this._withProvider(provider => provider.recordMissedTranslationOpportunity(language));
},
/**
* Record a translation in the health report.
* @param langFrom
@ -337,9 +355,11 @@ TranslationMeasurement1.prototype = Object.freeze({
fields: {
translationOpportunityCount: DAILY_COUNTER_FIELD,
missedTranslationOpportunityCount: DAILY_COUNTER_FIELD,
pageTranslatedCount: DAILY_COUNTER_FIELD,
charactersTranslatedCount: DAILY_COUNTER_FIELD,
translationOpportunityCountsByLanguage: DAILY_LAST_TEXT_FIELD,
missedTranslationOpportunityCountsByLanguage: DAILY_LAST_TEXT_FIELD,
pageTranslatedCountsByLanguage: DAILY_LAST_TEXT_FIELD,
detectedLanguageChangedBefore: DAILY_COUNTER_FIELD,
detectedLanguageChangedAfter: DAILY_COUNTER_FIELD,
@ -384,6 +404,7 @@ TranslationMeasurement1.prototype = Object.freeze({
// Special case the serialization of these fields so that
// they are sent as objects, not stringified objects.
_parseInPlace(result, "translationOpportunityCountsByLanguage");
_parseInPlace(result, "missedTranslationOpportunityCountsByLanguage");
_parseInPlace(result, "pageTranslatedCountsByLanguage");
return result;
@ -423,6 +444,25 @@ TranslationProvider.prototype = Object.freeze({
}.bind(this));
},
recordMissedTranslationOpportunity: function (language, date=new Date()) {
let m = this.getMeasurement(TranslationMeasurement1.prototype.name,
TranslationMeasurement1.prototype.version);
return this._enqueueTelemetryStorageTask(function* recordTask() {
yield m.incrementDailyCounter("missedTranslationOpportunityCount", date);
let langCounts = yield m._getDailyLastTextFieldAsJSON(
"missedTranslationOpportunityCountsByLanguage", date);
langCounts[language] = (langCounts[language] || 0) + 1;
langCounts = JSON.stringify(langCounts);
yield m.setDailyLastText("missedTranslationOpportunityCountsByLanguage",
langCounts, date);
}.bind(this));
},
recordTranslation: function (langFrom, langTo, numCharacters, date=new Date()) {
let m = this.getMeasurement(TranslationMeasurement1.prototype.name,
TranslationMeasurement1.prototype.version);

View File

@ -69,21 +69,47 @@ add_task(function* test_translation_opportunity() {
let countsByLanguage = JSON.parse(day.get("translationOpportunityCountsByLanguage"));
Assert.equal(countsByLanguage["fr"], 1);
// Record a missed opportunity.
yield provider.recordMissedTranslationOpportunity("it", now);
values = yield m.getValues();
day = values.days.getDay(now);
Assert.equal(values.days.size, 1);
Assert.ok(values.days.hasDay(now));
Assert.ok(day.has("missedTranslationOpportunityCount"));
Assert.equal(day.get("missedTranslationOpportunityCount"), 1);
Assert.ok(day.has("missedTranslationOpportunityCountsByLanguage"));
let missedCountsByLanguage = JSON.parse(day.get("missedTranslationOpportunityCountsByLanguage"));
Assert.equal(missedCountsByLanguage["it"], 1);
// Record more opportunities.
yield provider.recordTranslationOpportunity("fr", now);
yield provider.recordTranslationOpportunity("fr", now);
yield provider.recordTranslationOpportunity("es", now);
yield provider.recordMissedTranslationOpportunity("it", now);
yield provider.recordMissedTranslationOpportunity("cs", now);
yield provider.recordMissedTranslationOpportunity("fi", now);
values = yield m.getValues();
let day = values.days.getDay(now);
day = values.days.getDay(now);
Assert.ok(day.has("translationOpportunityCount"));
Assert.equal(day.get("translationOpportunityCount"), 4);
Assert.ok(day.has("missedTranslationOpportunityCount"));
Assert.equal(day.get("missedTranslationOpportunityCount"), 4);
Assert.ok(day.has("translationOpportunityCountsByLanguage"));
countsByLanguage = JSON.parse(day.get("translationOpportunityCountsByLanguage"));
Assert.equal(countsByLanguage["fr"], 3);
Assert.equal(countsByLanguage["es"], 1);
Assert.ok(day.has("missedTranslationOpportunityCountsByLanguage"));
missedCountsByLanguage = JSON.parse(day.get("missedTranslationOpportunityCountsByLanguage"));
Assert.equal(missedCountsByLanguage["it"], 2);
Assert.equal(missedCountsByLanguage["cs"], 1);
Assert.equal(missedCountsByLanguage["fi"], 1);
yield provider.shutdown();
yield storage.close();
});

View File

@ -190,11 +190,11 @@ Section "MaintenanceService"
${GetParameters} $0
${GetOptions} "$0" "/Upgrade" $0
${If} ${Errors}
nsExec::Exec '"$INSTDIR\$TempMaintServiceName" install'
ExecWait '"$INSTDIR\$TempMaintServiceName" install'
${Else}
; The upgrade cmdline is the same as install except
; It will fail if the service isn't already installed.
nsExec::Exec '"$INSTDIR\$TempMaintServiceName" upgrade'
ExecWait '"$INSTDIR\$TempMaintServiceName" upgrade'
${EndIf}
WriteUninstaller "$INSTDIR\Uninstall.exe"
@ -255,7 +255,7 @@ FunctionEnd
Section "Uninstall"
; Delete the service so that no updates will be attempted
nsExec::Exec '"$INSTDIR\maintenanceservice.exe" uninstall'
ExecWait '"$INSTDIR\maintenanceservice.exe" uninstall'
Push "$INSTDIR\updater.ini"
Call un.RenameDelete

View File

@ -197,11 +197,7 @@ if test "$CLANG_CXX"; then
## returned by C functions. This is possible because we use knowledge about the ABI
## to typedef it to a C type with the same layout when the headers are included
## from C.
##
## mismatched-tags is disabled (bug 780474) mostly because it's useless.
## Worse, it's not supported by gcc, so it will cause tryserver bustage
## without any easy way for non-Clang users to check for it.
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-mismatched-tags"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
fi
AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) actually is a C++ compiler])
@ -216,15 +212,6 @@ LIBS=$_SAVE_LIBS
AC_LANG_RESTORE
AC_MSG_RESULT([yes])
if test -z "$GNU_CC"; then
case "$target" in
*-mingw*)
## Warning 4099 (equivalent of mismatched-tags) is disabled (bug 780474)
## for the same reasons as above.
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -wd4099"
esac
fi
if test -n "$DEVELOPER_OPTIONS"; then
MOZ_FORCE_GOLD=1
fi

View File

@ -194,7 +194,7 @@ class B2GRemoteAutomation(Automation):
time.sleep(10)
self._devicemanager._checkCmd(['shell', 'start', 'b2g'])
if self._is_emulator:
self.marionette.emulator.wait_for_port()
self.marionette.emulator.wait_for_port(self.marionette.port)
def rebootDevice(self):
# find device's current status and serial number
@ -262,7 +262,7 @@ class B2GRemoteAutomation(Automation):
'tcp:%s' % self.marionette.port])
if self._is_emulator:
self.marionette.emulator.wait_for_port()
self.marionette.emulator.wait_for_port(self.marionette.port)
else:
time.sleep(5)

View File

@ -131,7 +131,7 @@ class MachCommands(MachCommandBase):
binary=self.get_binary_path(),
cmdargs=firefox_args,
env=env,
kp_kwargs=kp_kwargs)
process_args=kp_kwargs)
runner.start(debug_args=valgrind_args)
exitcode = runner.wait()

View File

@ -2040,11 +2040,8 @@ public:
*
* @return whether aAttr was valid and can be cached.
*/
static AutocompleteAttrState
SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
nsAString& aResult,
AutocompleteAttrState aCachedState =
eAutocompleteAttrState_Unknown);
static AutocompleteAttrState SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
nsAString& aResult);
/**
* This will parse aSource, to extract the value of the pseudo attribute

View File

@ -855,26 +855,8 @@ nsContentUtils::IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput)
nsContentUtils::AutocompleteAttrState
nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
nsAString& aResult,
AutocompleteAttrState aCachedState)
nsAString& aResult)
{
if (!aAttr ||
aCachedState == nsContentUtils::eAutocompleteAttrState_Invalid) {
return aCachedState;
}
if (aCachedState == nsContentUtils::eAutocompleteAttrState_Valid) {
uint32_t atomCount = aAttr->GetAtomCount();
for (uint32_t i = 0; i < atomCount; i++) {
if (i != 0) {
aResult.Append(' ');
}
aResult.Append(nsDependentAtomString(aAttr->AtomAt(i)));
}
nsContentUtils::ASCIIToLower(aResult);
return aCachedState;
}
AutocompleteAttrState state = InternalSerializeAutocompleteAttribute(aAttr, aResult);
if (state == eAutocompleteAttrState_Valid) {
ASCIIToLower(aResult);
@ -891,7 +873,7 @@ nsContentUtils::SerializeAutocompleteAttribute(const nsAttrValue* aAttr,
*/
nsContentUtils::AutocompleteAttrState
nsContentUtils::InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrVal,
nsAString& aResult)
nsAString& aResult)
{
// No sandbox attribute so we are done
if (!aAttrVal) {

View File

@ -1520,10 +1520,23 @@ HTMLInputElement::GetAutocomplete(nsAString& aValue)
{
aValue.Truncate(0);
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
if (!attributeVal ||
mAutocompleteAttrState == nsContentUtils::eAutocompleteAttrState_Invalid) {
return NS_OK;
}
if (mAutocompleteAttrState == nsContentUtils::eAutocompleteAttrState_Valid) {
uint32_t atomCount = attributeVal->GetAtomCount();
for (uint32_t i = 0; i < atomCount; i++) {
if (i != 0) {
aValue.Append(' ');
}
aValue.Append(nsDependentAtomString(attributeVal->AtomAt(i)));
}
nsContentUtils::ASCIIToLower(aValue);
return NS_OK;
}
mAutocompleteAttrState =
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
mAutocompleteAttrState);
mAutocompleteAttrState = nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue);
return NS_OK;
}

View File

@ -104,7 +104,6 @@ HTMLSelectElement::HTMLSelectElement(already_AddRefed<nsINodeInfo>& aNodeInfo,
FromParser aFromParser)
: nsGenericHTMLFormElementWithState(aNodeInfo),
mOptions(new HTMLOptionsCollection(MOZ_THIS_IN_INITIALIZER_LIST())),
mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
mIsDoneAddingChildren(!aFromParser),
mDisabledChanged(false),
mMutating(false),
@ -178,16 +177,6 @@ HTMLSelectElement::SetCustomValidity(const nsAString& aError)
return NS_OK;
}
void
HTMLSelectElement::GetAutocomplete(DOMString& aValue)
{
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
mAutocompleteAttrState =
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
mAutocompleteAttrState);
}
NS_IMETHODIMP
HTMLSelectElement::GetForm(nsIDOMHTMLFormElement** aForm)
{
@ -1344,9 +1333,6 @@ HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
UpdateBarredFromConstraintValidation();
} else if (aName == nsGkAtoms::required) {
UpdateValueMissingValidityState();
} else if (aName == nsGkAtoms::autocomplete) {
// Clear the cached @autocomplete attribute state
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
}
UpdateState(aNotify);
@ -1434,13 +1420,8 @@ HTMLSelectElement::ParseAttribute(int32_t aNamespaceID,
const nsAString& aValue,
nsAttrValue& aResult)
{
if (kNameSpaceID_None == aNamespaceID) {
if (aAttribute == nsGkAtoms::size) {
return aResult.ParsePositiveIntValue(aValue);
} else if (aAttribute == nsGkAtoms::autocomplete) {
aResult.ParseAtomArray(aValue);
return true;
}
if (aAttribute == nsGkAtoms::size && kNameSpaceID_None == aNamespaceID) {
return aResult.ParsePositiveIntValue(aValue);
}
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
aResult);

View File

@ -17,7 +17,6 @@
#include "nsCOMPtr.h"
#include "nsError.h"
#include "mozilla/dom/HTMLFormElement.h"
#include "nsContentUtils.h"
class nsContentList;
class nsIDOMHTMLOptionElement;
@ -160,11 +159,6 @@ public:
{
SetHTMLBoolAttr(nsGkAtoms::autofocus, aVal, aRv);
}
void GetAutocomplete(DOMString& aValue);
void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv)
{
SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
}
bool Disabled() const
{
return GetBoolAttr(nsGkAtoms::disabled);
@ -611,7 +605,6 @@ protected:
/** The options[] array */
nsRefPtr<HTMLOptionsCollection> mOptions;
nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
/** false if the parser is in the middle of adding children. */
bool mIsDoneAddingChildren;
/** true if our disabled state has changed from the default **/

View File

@ -13,8 +13,7 @@ Test @autocomplete on <input>
<p id="display"></p>
<div id="content" style="display: none">
<form>
<input id="input-field" />
<select id="select-field" />
<input id="field" />
</form>
</div>
<pre id="test">
@ -70,8 +69,9 @@ var values = [
];
var types = [undefined, "hidden", "text", "search"]; // Valid types for all non-multiline hints.
var field = document.getElementById("field");
function checkAutocompleteValues(field, type) {
function checkAutocompleteValues(type) {
for (var test of values) {
if (typeof(test[0]) === "undefined")
field.removeAttribute("autocomplete");
@ -83,18 +83,14 @@ function checkAutocompleteValues(field, type) {
}
function start() {
var inputField = document.getElementById("input-field");
for (var type of types) {
// Switch the input type
if (typeof(type) === "undefined")
inputField.removeAttribute("type");
field.removeAttribute("type");
else
inputField.type = type;
checkAutocompleteValues(inputField, type || "");
field.type = type;
checkAutocompleteValues(type || "");
}
var selectField = document.getElementById("select-field");
checkAutocompleteValues(selectField, "select");
SimpleTest.finish();
}

View File

@ -616,12 +616,13 @@ this.DOMApplicationRegistry = {
}.bind(this)).then(null, Cu.reportError);
},
updateDataStore: function(aId, aOrigin, aManifestURL, aManifest, aAppStatus) {
// Just Certified Apps can use DataStores
let prefName = "dom.testing.datastore_enabled_for_hosted_apps";
if (aAppStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED &&
(Services.prefs.getPrefType(prefName) == Services.prefs.PREF_INVALID ||
!Services.prefs.getBoolPref(prefName))) {
updateDataStore: function(aId, aOrigin, aManifestURL, aManifest) {
let uri = Services.io.newURI(aOrigin, null, null);
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let principal = secMan.getAppCodebasePrincipal(uri, aId,
/*mozbrowser*/ false);
if (!dataStoreService.checkPermission(principal)) {
return;
}
@ -1543,7 +1544,7 @@ this.DOMApplicationRegistry = {
true);
}
this.updateDataStore(this.webapps[id].localId, app.origin,
app.manifestURL, newManifest, app.appStatus);
app.manifestURL, newManifest);
this.broadcastMessage("Webapps:UpdateState", {
app: app,
manifest: newManifest,
@ -1961,7 +1962,7 @@ this.DOMApplicationRegistry = {
}
this.updateDataStore(this.webapps[aId].localId, aApp.origin,
aApp.manifestURL, aApp.manifest, aApp.appStatus);
aApp.manifestURL, aApp.manifest);
aApp.name = manifest.name;
aApp.csp = manifest.csp || "";
@ -2494,8 +2495,7 @@ this.DOMApplicationRegistry = {
}
this.updateDataStore(this.webapps[id].localId, this.webapps[id].origin,
this.webapps[id].manifestURL, jsonManifest,
this.webapps[id].appStatus);
this.webapps[id].manifestURL, jsonManifest);
}
for each (let prop in ["installState", "downloadAvailable", "downloading",
@ -2631,7 +2631,7 @@ this.DOMApplicationRegistry = {
}
this.updateDataStore(this.webapps[aId].localId, aNewApp.origin,
aNewApp.manifestURL, aManifest, aNewApp.appStatus);
aNewApp.manifestURL, aManifest);
this.broadcastMessage("Webapps:UpdateState", {
app: app,

View File

@ -2264,25 +2264,7 @@ Navigator::HasDataStoreSupport(nsIPrincipal* aPrincipal)
{
workers::AssertIsOnMainThread();
// First of all, the general pref has to be turned on.
bool enabled = false;
Preferences::GetBool("dom.datastore.enabled", &enabled);
if (!enabled) {
return false;
}
// Just for testing, we can enable DataStore for any kind of app.
if (Preferences::GetBool("dom.testing.datastore_enabled_for_hosted_apps", false)) {
return true;
}
uint16_t status;
if (NS_FAILED(aPrincipal->GetAppStatus(&status))) {
return false;
}
// Only support DataStore API for certified apps for now.
return status == nsIPrincipal::APP_STATUS_CERTIFIED;
return DataStoreService::CheckPermission(aPrincipal);
}
// A WorkerMainThreadRunnable to synchronously dispatch the call of

View File

@ -0,0 +1,243 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CameraPreferences.h"
#include "CameraCommon.h"
#include "mozilla/Monitor.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
/* statics */
static StaticAutoPtr<Monitor> sPrefMonitor;
StaticAutoPtr<nsCString> CameraPreferences::sPrefTestEnabled;
StaticAutoPtr<nsCString> CameraPreferences::sPrefHardwareTest;
StaticAutoPtr<nsCString> CameraPreferences::sPrefGonkParameters;
nsresult CameraPreferences::sPrefCameraControlMethodErrorOverride = NS_OK;
nsresult CameraPreferences::sPrefCameraControlAsyncErrorOverride = NS_OK;
/* static */
nsresult
CameraPreferences::UpdatePref(const char* aPref, nsresult& aVal)
{
uint32_t val;
nsresult rv = Preferences::GetUint(aPref, &val);
if (NS_SUCCEEDED(rv)) {
aVal = static_cast<nsresult>(val);
}
return rv;
}
/* static */
nsresult
CameraPreferences::UpdatePref(const char* aPref, nsACString& aVal)
{
nsCString val;
nsresult rv = Preferences::GetCString(aPref, &val);
if (NS_SUCCEEDED(rv)) {
aVal = val;
}
return rv;
}
/* static */
CameraPreferences::Pref CameraPreferences::sPrefs[] = {
{
"camera.control.test.enabled",
kPrefValueIsCString,
{ &sPrefTestEnabled }
},
{
"camera.control.test.hardware",
kPrefValueIsCString,
{ &sPrefHardwareTest }
},
#ifdef MOZ_B2G
{
"camera.control.test.hardware.gonk.parameters",
kPrefValueIsCString,
{ &sPrefGonkParameters }
},
#endif
{
"camera.control.test.method.error",
kPrefValueIsNSResult,
{ &sPrefCameraControlMethodErrorOverride }
},
{
"camera.control.test.async.error",
kPrefValueIsNSResult,
{ &sPrefCameraControlAsyncErrorOverride }
},
};
/* static */
uint32_t
CameraPreferences::PrefToIndex(const char* aPref)
{
for (uint32_t i = 0; i < ArrayLength(sPrefs); ++i) {
if (strcmp(aPref, sPrefs[i].mPref) == 0) {
return i;
}
}
return kPrefNotFound;
}
/* static */
void
CameraPreferences::PreferenceChanged(const char* aPref, void* aClosure)
{
MonitorAutoLock mon(*sPrefMonitor);
uint32_t i = PrefToIndex(aPref);
if (i == kPrefNotFound) {
DOM_CAMERA_LOGE("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return;
}
Pref& p = sPrefs[i];
nsresult rv;
switch (p.mValueType) {
case kPrefValueIsNSResult:
{
nsresult& v = *p.mValue.mAsNsResult;
rv = UpdatePref(aPref, v);
if (NS_SUCCEEDED(rv)) {
DOM_CAMERA_LOGI("Preference '%s' has changed, 0x%x\n", aPref, v);
}
}
break;
case kPrefValueIsCString:
{
nsCString& v = **p.mValue.mAsCString;
rv = UpdatePref(aPref, v);
if (NS_SUCCEEDED(rv)) {
DOM_CAMERA_LOGI("Preference '%s' has changed, '%s'\n", aPref, v.get());
}
}
break;
default:
MOZ_ASSERT_UNREACHABLE("Unhandled preference value type!");
return;
}
#ifdef DEBUG
if (NS_FAILED(rv)) {
nsCString msg;
msg.AppendPrintf("Failed to update pref '%s' (0x%x)\n", aPref, rv);
NS_WARNING(msg.get());
}
#endif
}
/* static */
bool
CameraPreferences::Initialize()
{
DOM_CAMERA_LOGI("Initializing camera preference callbacks\n");
nsresult rv;
sPrefMonitor = new Monitor("CameraPreferences.sPrefMonitor");
sPrefTestEnabled = new nsCString();
sPrefHardwareTest = new nsCString();
sPrefGonkParameters = new nsCString();
for (uint32_t i = 0; i < ArrayLength(sPrefs); ++i) {
rv = Preferences::RegisterCallbackAndCall(CameraPreferences::PreferenceChanged,
sPrefs[i].mPref);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
}
DOM_CAMERA_LOGI("Camera preferences initialized\n");
return true;
}
/* static */
void
CameraPreferences::Shutdown()
{
DOM_CAMERA_LOGI("Shutting down camera preference callbacks\n");
for (uint32_t i = 0; i < ArrayLength(sPrefs); ++i) {
Preferences::UnregisterCallback(CameraPreferences::PreferenceChanged,
sPrefs[i].mPref);
}
sPrefTestEnabled = nullptr;
sPrefHardwareTest = nullptr;
sPrefGonkParameters = nullptr;
sPrefMonitor = nullptr;
DOM_CAMERA_LOGI("Camera preferences shut down\n");
}
/* static */
bool
CameraPreferences::GetPref(const char* aPref, nsACString& aVal)
{
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
MonitorAutoLock mon(*sPrefMonitor);
uint32_t i = PrefToIndex(aPref);
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return false;
}
if (sPrefs[i].mValueType != kPrefValueIsCString) {
DOM_CAMERA_LOGW("Preference '%s' is not a string type\n", aPref);
return false;
}
StaticAutoPtr<nsCString>* s = sPrefs[i].mValue.mAsCString;
if (!*s) {
DOM_CAMERA_LOGE("Preference '%s' cache is not initialized\n", aPref);
return false;
}
if ((*s)->IsEmpty()) {
DOM_CAMERA_LOGI("Preference '%s' is not set\n", aPref);
return false;
}
DOM_CAMERA_LOGI("Preference '%s', got '%s'\n", aPref, (*s)->get());
aVal = **s;
return true;
}
/* static */
bool
CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
{
MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
MonitorAutoLock mon(*sPrefMonitor);
uint32_t i = PrefToIndex(aPref);
if (i == kPrefNotFound || i >= ArrayLength(sPrefs)) {
DOM_CAMERA_LOGW("Preference '%s' is not tracked by CameraPreferences\n", aPref);
return false;
}
if (sPrefs[i].mValueType != kPrefValueIsNSResult) {
DOM_CAMERA_LOGW("Preference '%s' is not an nsresult type\n", aPref);
return false;
}
nsresult v = *sPrefs[i].mValue.mAsNsResult;
if (v == NS_OK) {
DOM_CAMERA_LOGI("Preference '%s' is not set\n", aPref);
return false;
}
DOM_CAMERA_LOGI("Preference '%s', got 0x%x\n", aPref, v);
aVal = v;
return true;
}

View File

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_CAMERA_CAMERAPREFERENCES_H
#define DOM_CAMERA_CAMERAPREFERENCES_H
#include "nsString.h"
namespace mozilla {
template<class T> class StaticAutoPtr;
class CameraPreferences
{
public:
static bool Initialize();
static void Shutdown();
static bool GetPref(const char* aPref, nsACString& aVal);
static bool GetPref(const char* aPref, nsresult& aVal);
protected:
static const uint32_t kPrefNotFound = UINT32_MAX;
static uint32_t PrefToIndex(const char* aPref);
static void PreferenceChanged(const char* aPref, void* aClosure);
static nsresult UpdatePref(const char* aPref, nsresult& aVar);
static nsresult UpdatePref(const char* aPref, nsACString& aVar);
enum PrefValueType {
kPrefValueIsNSResult,
kPrefValueIsCString
};
struct Pref {
const char* const mPref;
PrefValueType mValueType;
union {
// The 'mAsVoid' member must be first and is required to allow 'mValue'
// to be initialized with any pointer type, as not all of our platforms
// support the use of designated initializers; in their absence, only
// the first element of a union can be statically initialized, and
// 'void*' lets us stuff any pointer type into it.
void* mAsVoid;
StaticAutoPtr<nsCString>* mAsCString;
nsresult* mAsNsResult;
} mValue;
};
static Pref sPrefs[];
static StaticAutoPtr<nsCString> sPrefTestEnabled;
static StaticAutoPtr<nsCString> sPrefHardwareTest;
static StaticAutoPtr<nsCString> sPrefGonkParameters;
static nsresult sPrefCameraControlMethodErrorOverride;
static nsresult sPrefCameraControlAsyncErrorOverride;
private:
// static class only
CameraPreferences();
~CameraPreferences();
};
} // namespace mozilla
#endif // DOM_CAMERA_CAMERAPREFERENCES_H

View File

@ -23,7 +23,7 @@
#include "base/basictypes.h"
#include "nsDebug.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/Preferences.h"
#include "CameraPreferences.h"
#include "mozilla/RefPtr.h"
#include "GonkCameraControl.h"
#include "GonkNativeWindow.h"
@ -212,8 +212,8 @@ GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCam
return nullptr;
}
const nsAdoptingCString& test =
mozilla::Preferences::GetCString("camera.control.test.enabled");
nsCString test;
CameraPreferences::GetPref("camera.control.test.enabled", test);
sp<GonkCameraHardware> cameraHardware;
if (test.EqualsASCII("hardware")) {
NS_WARNING("Using test Gonk hardware layer");

View File

@ -20,7 +20,7 @@
#include "CameraCommon.h"
#include "GonkCameraControl.h"
#include "mozilla/Preferences.h"
#include "CameraPreferences.h"
#include "TestGonkCameraControl.h"
using namespace mozilla;
@ -117,13 +117,12 @@ ICameraControl::GetListOfCameras(nsTArray<nsString>& aList)
return NS_OK;
}
static const char* sTestModeEnabled = "camera.control.test.enabled";
// implementation-specific camera factory
already_AddRefed<ICameraControl>
ICameraControl::Create(uint32_t aCameraId)
{
const nsAdoptingCString& test = Preferences::GetCString(sTestModeEnabled);
nsCString test;
CameraPreferences::GetPref("camera.control.test.enabled", test);
nsRefPtr<nsGonkCameraControl> control;
if (test.EqualsASCII("control")) {
NS_WARNING("Using test CameraControl layer");

View File

@ -15,13 +15,10 @@
*/
#include "TestGonkCameraControl.h"
#include "mozilla/Preferences.h"
#include "CameraPreferences.h"
using namespace mozilla;
static const char* sMethodErrorOverride = "camera.control.test.method.error";
static const char* sAsyncErrorOverride = "camera.control.test.async.error";
TestGonkCameraControl::TestGonkCameraControl(uint32_t aCameraId)
: nsGonkCameraControl(aCameraId)
{
@ -37,9 +34,8 @@ TestGonkCameraControl::~TestGonkCameraControl()
nsresult
TestGonkCameraControl::ForceMethodFailWithCodeInternal(const char* aFile, int aLine)
{
nsresult rv =
static_cast<nsresult>(Preferences::GetInt(sMethodErrorOverride,
static_cast<int32_t>(NS_OK)));
nsresult rv = NS_OK;
CameraPreferences::GetPref("camera.control.test.method.error", rv);
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGI("[%s:%d] CameraControl method error override: 0x%x\n",
aFile, aLine, rv);
@ -50,9 +46,8 @@ TestGonkCameraControl::ForceMethodFailWithCodeInternal(const char* aFile, int aL
nsresult
TestGonkCameraControl::ForceAsyncFailWithCodeInternal(const char* aFile, int aLine)
{
nsresult rv =
static_cast<nsresult>(Preferences::GetInt(sAsyncErrorOverride,
static_cast<int32_t>(NS_OK)));
nsresult rv = NS_OK;
CameraPreferences::GetPref("camera.control.test.async.error", rv);
if (NS_FAILED(rv)) {
DOM_CAMERA_LOGI("[%s:%d] CameraControl async error override: 0x%x\n",
aFile, aLine, rv);

View File

@ -16,7 +16,7 @@
#include "TestGonkCameraHardware.h"
#include "mozilla/Preferences.h"
#include "CameraPreferences.h"
#include "nsThreadUtils.h"
using namespace android;
@ -52,7 +52,8 @@ TestGonkCameraHardware::Init()
const nsCString
TestGonkCameraHardware::TestCase()
{
const nsCString test = Preferences::GetCString("camera.control.test.hardware");
nsCString test;
CameraPreferences::GetPref("camera.control.test.hardware", test);
return test;
}
@ -77,7 +78,8 @@ TestGonkCameraHardware::GetExtraParameters()
* may contain equals signs or semicolons. We don't enforce that here
* so that we can also test correct handling of improperly-formatted values.
*/
const nsCString parameters = Preferences::GetCString("camera.control.test.hardware.gonk.parameters");
nsCString parameters;
CameraPreferences::GetPref("camera.control.test.hardware.gonk.parameters", parameters);
DOM_CAMERA_LOGA("TestGonkCameraHardware : extra-parameters '%s'\n",
parameters.get());
return parameters;

View File

@ -9,13 +9,13 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
EXPORTS += [
'CameraCommon.h',
'CameraPreviewMediaStream.h',
'CameraPreferences.h',
'DOMCameraManager.h',
'GonkCameraControl.h',
]
SOURCES += [
'CameraControlImpl.cpp',
'CameraPreferences.cpp',
'CameraPreviewMediaStream.cpp',
'CameraRecorderProfiles.cpp',
'DOMCameraCapabilities.cpp',

View File

@ -19,6 +19,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageBroadcaster");
XPCOMUtils.defineLazyServiceGetter(this, "dataStoreService",
"@mozilla.org/datastore-service;1",
"nsIDataStoreService");
this.DataStoreChangeNotifier = {
children: [],
messages: [ "DataStore:Changed", "DataStore:RegisterForMessages",
@ -65,17 +69,21 @@ this.DataStoreChangeNotifier = {
receiveMessage: function(aMessage) {
debug("receiveMessage");
debug("receiveMessage ");
// No check has to be done when the message is 'child-process-shutdown'
// because at this point the target is already disconnected from
// nsFrameMessageManager, so that assertAppHasStatus will always fail.
let prefName = 'dom.testing.datastore_enabled_for_hosted_apps';
if (aMessage.name != 'child-process-shutdown' &&
(Services.prefs.getPrefType(prefName) == Services.prefs.PREF_INVALID ||
!Services.prefs.getBoolPref(prefName)) &&
!aMessage.target.assertAppHasStatus(Ci.nsIPrincipal.APP_STATUS_CERTIFIED)) {
return;
// No check has to be done when the message is 'child-process-shutdown'.
if (aMessage.name != "child-process-shutdown") {
if (!("principal" in aMessage)) {
return;
}
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let uri = Services.io.newURI(aMessage.principal.origin, null, null);
let principal = secMan.getAppCodebasePrincipal(uri,
aMessage.principal.appId, aMessage.principal.isInBrowserElement);
if (!principal || !dataStoreService.checkPermission(principal)) {
return;
}
}
switch (aMessage.name) {

View File

@ -100,7 +100,9 @@ DataStore.prototype = {
cpmm.addMessageListener("DataStore:Changed:Return:OK", this);
cpmm.sendAsyncMessage("DataStore:RegisterForMessages",
{ store: this._name, owner: this._owner,
innerWindowID: this._innerWindowID });
innerWindowID: this._innerWindowID },
null,
this._window.document.nodePrincipal);
},
observe: function(aSubject, aTopic, aData) {
@ -110,7 +112,9 @@ DataStore.prototype = {
cpmm.removeMessageListener("DataStore:Changed:Return:OK", this);
cpmm.sendAsyncMessage("DataStore:UnregisterForMessages",
{ innerWindowID: this._innerWindowID });
{ innerWindowID: this._innerWindowID },
null,
this._window.document.nodePrincipal);
this._shuttingdown = true;
this._db.close();
}
@ -336,7 +340,9 @@ DataStore.prototype = {
cpmm.sendAsyncMessage("DataStore:Changed",
{ store: this.name, owner: this._owner,
message: { revisionId: aRevisionId, id: aId,
operation: aOperation, owner: this._owner } } );
operation: aOperation, owner: this._owner } },
null,
this._window.document.nodePrincipal);
},
receiveMessage: function(aMessage) {

View File

@ -903,7 +903,7 @@ DataStoreService::GetDataStores(nsIDOMWindow* aWindow,
return NS_OK;
}
rv = GetDataStoreInfos(aName, appId, stores);
rv = GetDataStoreInfos(aName, appId, principal, stores);
if (NS_FAILED(rv)) {
RejectPromise(window, promise, rv);
promise.forget(aDataStores);
@ -1043,6 +1043,7 @@ DataStoreService::GetDataStoresResolve(nsPIDOMWindow* aWindow,
nsresult
DataStoreService::GetDataStoreInfos(const nsAString& aName,
uint32_t aAppId,
nsIPrincipal* aPrincipal,
nsTArray<DataStoreInfo>& aStores)
{
AssertIsInMainProcess();
@ -1064,15 +1065,7 @@ DataStoreService::GetDataStoreInfos(const nsAString& aName,
return NS_ERROR_DOM_SECURITY_ERR;
}
uint16_t status;
rv = app->GetAppStatus(&status);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (status != nsIPrincipal::APP_STATUS_CERTIFIED &&
!Preferences::GetBool("dom.testing.datastore_enabled_for_hosted_apps",
false)) {
if (!DataStoreService::CheckPermission(aPrincipal)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
@ -1095,6 +1088,45 @@ DataStoreService::GetDataStoreInfos(const nsAString& aName,
return NS_OK;
}
bool
DataStoreService::CheckPermission(nsIPrincipal* aPrincipal)
{
// First of all, the general pref has to be turned on.
bool enabled = false;
Preferences::GetBool("dom.datastore.enabled", &enabled);
if (!enabled) {
return false;
}
// Just for testing, we can enable DataStore for any kind of app.
if (Preferences::GetBool("dom.testing.datastore_enabled_for_hosted_apps", false)) {
return true;
}
if (!aPrincipal) {
return false;
}
uint16_t status;
if (NS_FAILED(aPrincipal->GetAppStatus(&status))) {
return false;
}
// Only support DataStore API for certified apps for now.
return status == nsIPrincipal::APP_STATUS_CERTIFIED;
}
NS_IMETHODIMP
DataStoreService::CheckPermission(nsIPrincipal* aPrincipal,
bool* aResult)
{
MOZ_ASSERT(NS_IsMainThread());
*aResult = DataStoreService::CheckPermission(aPrincipal);
return NS_OK;
}
// This method is called when an app with DataStores is deleted.
void
DataStoreService::DeleteDataStores(uint32_t aAppId)
@ -1311,7 +1343,7 @@ DataStoreService::GetDataStoresFromIPC(const nsAString& aName,
}
nsTArray<DataStoreInfo> stores;
rv = GetDataStoreInfos(aName, appId, stores);
rv = GetDataStoreInfos(aName, appId, aPrincipal, stores);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

View File

@ -48,6 +48,8 @@ public:
static void Shutdown();
static bool CheckPermission(nsIPrincipal* principal);
nsresult GenerateUUID(nsAString& aID);
nsresult GetDataStoresFromIPC(const nsAString& aName,
@ -82,6 +84,7 @@ private:
const nsTArray<DataStoreInfo>& aStores);
nsresult GetDataStoreInfos(const nsAString& aName, uint32_t aAppId,
nsIPrincipal* aPrincipal,
nsTArray<DataStoreInfo>& aStores);
void DeleteDataStores(uint32_t aAppId);

View File

@ -6,8 +6,9 @@
#include "nsISupports.idl"
interface nsIDOMWindow;
interface nsIPrincipal;
[scriptable, uuid(0a050c4f-d292-4a14-8712-09bc1019840a)]
[scriptable, uuid(43a731b9-0b5d-400a-8711-8c912c3c3572)]
interface nsIDataStoreService : nsISupports
{
void installDataStore(in unsigned long appId,
@ -24,4 +25,6 @@ interface nsIDataStoreService : nsISupports
nsISupports getDataStores(in nsIDOMWindow window,
in DOMString name);
boolean checkPermission(in nsIPrincipal principal);
};

View File

@ -10,8 +10,6 @@
interface HTMLSelectElement : HTMLElement {
[SetterThrows, Pure]
attribute boolean autofocus;
[Pref="dom.forms.autocomplete.experimental", SetterThrows, Pure]
attribute DOMString autocomplete;
[SetterThrows, Pure]
attribute boolean disabled;
[Pure]

View File

@ -126,8 +126,6 @@ TiledContentClient::UseTiledLayerBuffer(TiledBufferType aType)
}
SharedFrameMetricsHelper::SharedFrameMetricsHelper()
: mLastProgressiveUpdateWasLowPrecision(false)
, mProgressiveUpdateWasInDanger(false)
{
MOZ_COUNT_CTOR(SharedFrameMetricsHelper);
}
@ -175,17 +173,6 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
aCompositionBounds = ParentLayerRect(compositorMetrics.mCompositionBounds);
aZoom = compositorMetrics.GetZoomToParent();
// Reset the checkerboard risk flag when switching to low precision
// rendering.
if (aLowPrecision && !mLastProgressiveUpdateWasLowPrecision) {
// Skip low precision rendering until we're at risk of checkerboarding.
if (!mProgressiveUpdateWasInDanger) {
return true;
}
mProgressiveUpdateWasInDanger = false;
}
mLastProgressiveUpdateWasLowPrecision = aLowPrecision;
// Always abort updates if the resolution has changed. There's no use
// in drawing at the incorrect resolution.
if (!FuzzyEquals(compositorMetrics.GetZoom().scale, contentMetrics.GetZoom().scale)) {
@ -205,13 +192,20 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics(
return false;
}
// When not a low precision pass and the page is in danger of checker boarding
// abort update.
if (!aLowPrecision && !mProgressiveUpdateWasInDanger) {
if (AboutToCheckerboard(contentMetrics, compositorMetrics)) {
mProgressiveUpdateWasInDanger = true;
return true;
}
bool scrollUpdatePending = contentMetrics.GetScrollOffsetUpdated() &&
contentMetrics.GetScrollGeneration() != compositorMetrics.GetScrollGeneration();
// If scrollUpdatePending is true, then that means the content-side
// metrics has a new scroll offset that is going to be forced into the
// compositor but it hasn't gotten there yet.
// Even though right now comparing the metrics might indicate we're
// about to checkerboard (and that's true), the checkerboarding will
// disappear as soon as the new scroll offset update is processed
// on the compositor side. To avoid leaving things in a low-precision
// paint, we need to detect and handle this case (bug 1026756).
if (!aLowPrecision && !scrollUpdatePending && AboutToCheckerboard(contentMetrics, compositorMetrics)) {
TILING_PRLOG_OBJ(("TILING: Checkerboard abort content %s\n", tmpstr.get()), contentMetrics);
TILING_PRLOG_OBJ(("TILING: Checkerboard abort compositor %s\n", tmpstr.get()), compositorMetrics);
return true;
}
// Abort drawing stale low-precision content if there's a more recent

View File

@ -336,9 +336,6 @@ public:
*/
bool AboutToCheckerboard(const FrameMetrics& aContentMetrics,
const FrameMetrics& aCompositorMetrics);
private:
bool mLastProgressiveUpdateWasLowPrecision;
bool mProgressiveUpdateWasInDanger;
};
/**

View File

@ -133,7 +133,7 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
AddBlendModeEffect(effectChain);
nsIntRegion visibleRegion = GetEffectiveVisibleRegion();
const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
TiledLayerProperties tiledLayerProps;
if (mRequiresTiledProperties) {

View File

@ -755,7 +755,8 @@ NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label
masm.passABIArg(current_character);
masm.passABIArg(current_position);
masm.passABIArg(temp1);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, CaseInsensitiveCompareStrings));
int (*fun)(const jschar*, const jschar*, size_t) = CaseInsensitiveCompareStrings;
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, fun));
masm.storeCallResult(temp0);
masm.PopRegsInMask(volatileRegs);
@ -812,9 +813,12 @@ NativeRegExpMacroAssembler::CheckBitInTable(uint8_t *table, Label *on_bit_set)
{
IonSpew(SPEW_PREFIX "CheckBitInTable");
JS_ASSERT(mode_ != ASCII); // Ascii case not handled here.
masm.movePtr(ImmPtr(table), temp0);
// kTableMask is currently 127, so we need to mask even if the input is
// Latin1. V8 has the same issue.
static_assert(JSString::MAX_LATIN1_CHAR > kTableMask,
"No need to mask if MAX_LATIN1_CHAR <= kTableMask");
masm.move32(Imm32(kTableSize - 1), temp1);
masm.and32(current_character, temp1);
@ -875,7 +879,15 @@ NativeRegExpMacroAssembler::LoadCurrentCharacterUnchecked(int cp_offset, int cha
IonSpew(SPEW_PREFIX "LoadCurrentCharacterUnchecked(%d, %d)", cp_offset, characters);
if (mode_ == ASCII) {
MOZ_ASSUME_UNREACHABLE("Ascii loading not implemented");
BaseIndex address(input_end_pointer, current_position, TimesOne, cp_offset);
if (characters == 4) {
masm.load32(address, current_character);
} else if (characters == 2) {
masm.load16ZeroExtend(address, current_character);
} else {
JS_ASSERT(characters = 1);
masm.load8ZeroExtend(address, current_character);
}
} else {
JS_ASSERT(mode_ == JSCHAR);
JS_ASSERT(characters <= 2);

View File

@ -40,8 +40,8 @@ namespace irregexp {
struct InputOutputData
{
const jschar *inputStart;
const jschar *inputEnd;
const void *inputStart;
const void *inputEnd;
// Index into inputStart (in chars) at which to begin matching.
size_t startIndex;
@ -52,7 +52,8 @@ struct InputOutputData
// for global regexps.
int32_t result;
InputOutputData(const jschar *inputStart, const jschar *inputEnd,
template <typename CharT>
InputOutputData(const CharT *inputStart, const CharT *inputEnd,
size_t startIndex, MatchPairs *matches)
: inputStart(inputStart),
inputEnd(inputEnd),

View File

@ -1666,9 +1666,10 @@ irregexp::CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData
return compiler.Assemble(cx, assembler, node, data->capture_count);
}
template <typename CharT>
RegExpRunStatus
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
const jschar *chars, size_t start, size_t length, MatchPairs *matches)
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const CharT *chars, size_t start,
size_t length, MatchPairs *matches)
{
#ifdef JS_ION
typedef void (*RegExpCodeSignature)(InputOutputData *);
@ -1676,7 +1677,11 @@ irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
InputOutputData data(chars, chars + length, start, matches);
RegExpCodeSignature function = reinterpret_cast<RegExpCodeSignature>(codeBlock->raw());
CALL_GENERATED_REGEXP(function, &data);
{
JS::AutoSuppressGCAnalysis nogc;
CALL_GENERATED_REGEXP(function, &data);
}
return (RegExpRunStatus) data.result;
#else
@ -1684,6 +1689,14 @@ irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock,
#endif
}
template RegExpRunStatus
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const Latin1Char *chars, size_t start,
size_t length, MatchPairs *matches);
template RegExpRunStatus
irregexp::ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const jschar *chars, size_t start,
size_t length, MatchPairs *matches);
// -------------------------------------------------------------------
// Tree to graph conversion

View File

@ -108,13 +108,15 @@ CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
// 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 jschar *chars, size_t start, size_t length, MatchPairs *matches);
ExecuteCode(JSContext *cx, jit::JitCode *codeBlock, const CharT *chars, size_t start,
size_t length, MatchPairs *matches);
template <typename CharT>
RegExpRunStatus
InterpretCode(JSContext *cx, const uint8_t *byteCode,
const jschar *chars, size_t start, size_t length, MatchPairs *matches);
InterpretCode(JSContext *cx, const uint8_t *byteCode, const CharT *chars, size_t start,
size_t length, MatchPairs *matches);
#define FOR_EACH_NODE_TYPE(VISIT) \
VISIT(End) \

View File

@ -104,13 +104,14 @@ Load16Aligned(const uint8_t* pc)
#define BYTECODE(name) case BC_##name:
template <typename CharT>
RegExpRunStatus
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
const jschar *chars, size_t current, size_t length, MatchPairs *matches)
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode, const CharT *chars, size_t current,
size_t length, MatchPairs *matches)
{
const uint8_t* pc = byteCode;
jschar current_char = current ? chars[current - 1] : '\n';
uint32_t current_char = current ? chars[current - 1] : '\n';
RegExpStackCursor stack(cx);
@ -226,8 +227,8 @@ irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
if (pos + 2 > length) {
pc = byteCode + Load32Aligned(pc + 4);
} else {
jschar next = chars[pos + 1];
current_char = (chars[pos] | (next << (kBitsPerByte * sizeof(jschar))));
CharT next = chars[pos + 1];
current_char = (chars[pos] | (next << (kBitsPerByte * sizeof(CharT))));
pc += BC_LOAD_2_CURRENT_CHARS_LENGTH;
}
break;
@ -421,7 +422,7 @@ irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
pc = byteCode + Load32Aligned(pc + 4);
break;
}
if (CaseInsensitiveCompareStrings(chars + from, chars + current, len * 2)) {
if (CaseInsensitiveCompareStrings(chars + from, chars + current, len * sizeof(CharT))) {
current += len;
pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
} else {
@ -456,3 +457,11 @@ irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode,
}
}
}
template RegExpRunStatus
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode, const Latin1Char *chars, size_t current,
size_t length, MatchPairs *matches);
template RegExpRunStatus
irregexp::InterpretCode(JSContext *cx, const uint8_t *byteCode, const jschar *chars, size_t current,
size_t length, MatchPairs *matches);

View File

@ -35,12 +35,13 @@
using namespace js;
using namespace js::irregexp;
template <typename CharT>
int
irregexp::CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *substring2,
irregexp::CaseInsensitiveCompareStrings(const CharT *substring1, const CharT *substring2,
size_t byteLength)
{
JS_ASSERT(byteLength % 2 == 0);
size_t length = byteLength >> 1;
JS_ASSERT(byteLength % sizeof(CharT) == 0);
size_t length = byteLength / sizeof(CharT);
for (size_t i = 0; i < length; i++) {
jschar c1 = substring1[i];
@ -56,6 +57,14 @@ irregexp::CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *
return 1;
}
template int
irregexp::CaseInsensitiveCompareStrings(const Latin1Char *substring1, const Latin1Char *substring2,
size_t byteLength);
template int
irregexp::CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *substring2,
size_t byteLength);
InterpretedRegExpMacroAssembler::InterpretedRegExpMacroAssembler(LifoAlloc *alloc, RegExpShared *shared,
size_t numSavedRegisters)
: RegExpMacroAssembler(*alloc, shared, numSavedRegisters),

View File

@ -217,8 +217,9 @@ class MOZ_STACK_CLASS RegExpMacroAssembler
RegExpShared *shared;
};
template <typename CharT>
int
CaseInsensitiveCompareStrings(const jschar *substring1, const jschar *substring2, size_t byteLength);
CaseInsensitiveCompareStrings(const CharT *substring1, const CharT *substring2, size_t byteLength);
class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler : public RegExpMacroAssembler
{

View File

@ -0,0 +1,109 @@
// Test that on->off->on and off->on->off toggles don't crash.
function addRemove(dbg, g) {
dbg.addDebuggee(g);
var f = dbg.getNewestFrame();
while (f)
f = f.older;
dbg.removeDebuggee(g);
}
function removeAdd(dbg, g) {
dbg.removeDebuggee(g);
dbg.addDebuggee(g);
var f = dbg.getNewestFrame();
while (f)
f = f.older;
}
function newGlobalDebuggerPair(toggleSeq) {
var g = newGlobal();
var dbg = new Debugger;
if (toggleSeq == removeAdd)
dbg.addDebuggee(g);
g.eval("" + function f() { return g(); });
g.eval("" + function g() { return h(); });
g.eval("line0 = Error().lineNumber;");
g.eval("" + function h() {
for (var i = 0; i < 100; i++)
interruptIf(i == 95);
debugger;
return i;
});
setInterruptCallback(function () { return true; });
return [g, dbg];
}
function testInterrupt(toggleSeq) {
var [g, dbg] = newGlobalDebuggerPair(toggleSeq);
setInterruptCallback(function () {
toggleSeq(dbg, g);
return true;
});
assertEq(g.f(), 100);
}
function testPrologue(toggleSeq) {
var [g, dbg] = newGlobalDebuggerPair(toggleSeq);
dbg.onEnterFrame = function (f) {
if (f.callee && f.callee.name == "h")
toggleSeq(dbg, g);
};
assertEq(g.f(), 100);
}
function testEpilogue(toggleSeq) {
var [g, dbg] = newGlobalDebuggerPair(toggleSeq);
dbg.onEnterFrame = function (f) {
if (f.callee && f.callee.name == "h") {
f.onPop = function () {
toggleSeq(dbg, g);
};
}
};
assertEq(g.f(), 100);
}
function testTrap(toggleSeq) {
var [g, dbg] = newGlobalDebuggerPair(toggleSeq);
dbg.onEnterFrame = function (f) {
if (f.callee && f.callee.name == "h") {
var offs = f.script.getLineOffsets(g.line0 + 2);
assertEq(offs.length > 0, true);
f.script.setBreakpoint(offs[0], { hit: function () {
toggleSeq(dbg, g);
}});
}
};
assertEq(g.f(), 100);
}
function testDebugger(toggleSeq) {
var [g, dbg] = newGlobalDebuggerPair(toggleSeq);
dbg.onDebuggerStatement = function () {
toggleSeq(dbg, g);
};
assertEq(g.f(), 100);
}
testInterrupt(addRemove);
testInterrupt(removeAdd);
testPrologue(removeAdd);
testEpilogue(removeAdd);
testTrap(removeAdd);
testDebugger(removeAdd);

View File

@ -13,3 +13,21 @@ assertEq(re.source, "foo[bB]a\\r\u1200");
assertEq(re.multiline, true);
assertEq(re.ignoreCase, true);
assertEq(re.sticky, false);
re = /b[aA]r/;
// Latin1
assertEq(toLatin1("foobAr1234").search(re), 3);
assertEq(toLatin1("bar1234").search(re), 0);
assertEq(toLatin1("foobbr1234").search(re), -1);
// TwoByte
assertEq("foobAr1234\u1200".search(re), 3);
assertEq("bar1234\u1200".search(re), 0);
assertEq("foobbr1234\u1200".search(re), -1);
re = /abcdefghijklm[0-5]/;
assertEq(toLatin1("1abcdefghijklm4").search(re), 1);
assertEq("\u12001abcdefghijklm0".search(re), 2);
assertEq(toLatin1("1abcdefghijklm8").search(re), -1);
assertEq("\u12001abcdefghijklm8".search(re), -1);

View File

@ -0,0 +1,126 @@
function testDollarReplacement() {
// Latin1 input, pat and replacement
var s = toLatin1("Foobarbaz123");
var pat = toLatin1("bar");
assertEq(s.replace(pat, toLatin1("AA")), "FooAAbaz123");
assertEq(s.replace(pat, toLatin1("A$$A")), "FooA$Abaz123");
assertEq(s.replace(pat, toLatin1("A$`A")), "FooAFooAbaz123");
assertEq(s.replace(pat, toLatin1("A$&A")), "FooAbarAbaz123");
assertEq(s.replace(pat, toLatin1("A$'A")), "FooAbaz123Abaz123");
// Latin1 input and pat, TwoByte replacement
assertEq(s.replace(pat, "A\u1200"), "FooA\u1200baz123");
assertEq(s.replace(pat, "A$$\u1200"), "FooA$\u1200baz123");
assertEq(s.replace(pat, "A$`\u1200"), "FooAFoo\u1200baz123");
assertEq(s.replace(pat, "A$&\u1200"), "FooAbar\u1200baz123");
assertEq(s.replace(pat, "A$'\u1200"), "FooAbaz123\u1200baz123");
// TwoByte input, Latin1 pat and replacement
s = "Foobarbaz123\u1200";
assertEq(s.replace(pat, toLatin1("A")), "FooAbaz123\u1200");
assertEq(s.replace(pat, toLatin1("A$$")), "FooA$baz123\u1200");
assertEq(s.replace(pat, toLatin1("A$`")), "FooAFoobaz123\u1200");
assertEq(s.replace(pat, toLatin1("A$&")), "FooAbarbaz123\u1200");
assertEq(s.replace(pat, toLatin1("A$'")), "FooAbaz123\u1200baz123\u1200");
// TwoByte input and pat, Latin1 replacement
s = "Foobar\u1200baz123";
pat += "\u1200";
assertEq(s.replace(pat, toLatin1("AB")), "FooABbaz123");
assertEq(s.replace(pat, toLatin1("A$$B")), "FooA$Bbaz123");
assertEq(s.replace(pat, toLatin1("A$`B")), "FooAFooBbaz123");
assertEq(s.replace(pat, toLatin1("A$&B")), "FooAbar\u1200Bbaz123");
assertEq(s.replace(pat, toLatin1("A$'B")), "FooAbaz123Bbaz123");
// TwoByte input, pat and replacement
assertEq(s.replace(pat, "A\u1300"), "FooA\u1300baz123");
assertEq(s.replace(pat, "A$$\u1300"), "FooA$\u1300baz123");
assertEq(s.replace(pat, "A$`\u1300"), "FooAFoo\u1300baz123");
assertEq(s.replace(pat, "A$&\u1300"), "FooAbar\u1200\u1300baz123");
assertEq(s.replace(pat, "A$'\u1300"), "FooAbaz123\u1300baz123");
}
testDollarReplacement();
function testRegExp() {
var s = toLatin1("Foobar123bar234");
assertEq(s.replace(/bar\d\d/, "456"), "Foo4563bar234");
// Latin1 input and replacement
var re1 = /bar\d\d/;
var re2 = /bar\d\d/g;
assertEq(s.replace(re1, toLatin1("789")), "Foo7893bar234");
assertEq(s.replace(re2, toLatin1("789\u00ff")), "Foo789\u00ff3789\u00ff4");
// Latin1 input, TwoByte replacement
assertEq(s.replace(re1, "789\u1200"), "Foo789\u12003bar234");
assertEq(s.replace(re2, "789\u1200"), "Foo789\u12003789\u12004");
// TwoByte input, Latin1 replacement
s += "\u1200";
assertEq(s.replace(re1, toLatin1("7890")), "Foo78903bar234\u1200");
assertEq(s.replace(re2, toLatin1("7890\u00ff")), "Foo7890\u00ff37890\u00ff4\u1200");
// TwoByte input and replacement
assertEq(s.replace(re1, "789\u1200"), "Foo789\u12003bar234\u1200");
assertEq(s.replace(re2, "789\u1200"), "Foo789\u12003789\u12004\u1200");
}
testRegExp();
function testRegExpDollar() {
var s = toLatin1("Foobar123bar2345");
// Latin1 input and replacement
var re1 = /bar\d\d/;
var re2 = /bar(\d\d)/g;
assertEq(s.replace(re1, toLatin1("--$&--")), "Foo--bar12--3bar2345");
assertEq(s.replace(re2, toLatin1("--$'\u00ff--")), "Foo--3bar2345\xFF--3--45\xFF--45");
assertEq(s.replace(re2, toLatin1("--$`--")), "Foo--Foo--3--Foobar123--45");
// Latin1 input, TwoByte replacement
assertEq(s.replace(re1, "\u1200$$"), "Foo\u1200$3bar2345");
assertEq(s.replace(re2, "\u1200$1"), "Foo\u1200123\u12002345");
assertEq(s.replace(re2, "\u1200$'"), "Foo\u12003bar23453\u12004545");
// TwoByte input, Latin1 replacement
s += "\u1200";
assertEq(s.replace(re1, toLatin1("**$&**")), "Foo**bar12**3bar2345\u1200");
assertEq(s.replace(re2, toLatin1("**$1**")), "Foo**12**3**23**45\u1200");
assertEq(s.replace(re2, toLatin1("**$`**")), "Foo**Foo**3**Foobar123**45\u1200");
assertEq(s.replace(re2, toLatin1("**$'$$**")), "Foo**3bar2345\u1200$**3**45\u1200$**45\u1200");
// TwoByte input and replacement
assertEq(s.replace(re1, "**$&**\ueeee"), "Foo**bar12**\ueeee3bar2345\u1200");
assertEq(s.replace(re2, "**$1**\ueeee"), "Foo**12**\ueeee3**23**\ueeee45\u1200");
assertEq(s.replace(re2, "\ueeee**$`**"), "Foo\ueeee**Foo**3\ueeee**Foobar123**45\u1200");
assertEq(s.replace(re2, "\ueeee**$'$$**"), "Foo\ueeee**3bar2345\u1200$**3\ueeee**45\u1200$**45\u1200");
}
testRegExpDollar();
function testFlattenPattern() {
var s = "abcdef[g]abc";
// Latin1 pattern
assertEq(s.replace(toLatin1("def[g]"), "--$&--", "gi"), "abc--def[g]--abc");
// TwoByte pattern
s = "abcdef[g]\u1200abc";
assertEq(s.replace("def[g]\u1200", "++$&++", "gi"), "abc++def[g]\u1200++abc");
}
testFlattenPattern();
function testReplaceEmpty() {
// Latin1
var s = toLatin1("--abcdefghijkl--abcdefghijkl--abcdefghijkl--abcdefghijkl");
assertEq(s.replace(/abcd[eE]/g, ""), "--fghijkl--fghijkl--fghijkl--fghijkl");
s = "--abcdEf--";
assertEq(s.replace(/abcd[eE]/g, ""), "--f--");
// TwoByte
s = "--abcdefghijkl--abcdefghijkl--abcdefghijkl--abcdefghijkl\u1200";
assertEq(s.replace(/abcd[eE]/g, ""), "--fghijkl--fghijkl--fghijkl--fghijkl\u1200");
s = "--abcdEf--\u1200";
assertEq(s.replace(/abcd[eE]/g, ""), "--f--\u1200");
}
testReplaceEmpty();

View File

@ -50,23 +50,21 @@ struct DebugModeOSREntry
#ifdef DEBUG
MOZ_ASSERT(pcOffset == icEntry.pcOffset());
MOZ_ASSERT(frameKind == icEntry.kind());
#endif
}
// Assert that if we have a NonOp ICEntry, that there are no unsynced
// slots, since such a recompile could have only been triggered from
// either an interrupt check or a debug trap handler.
//
// If triggered from an interrupt check, the stack should be fully
// synced.
//
// If triggered from a debug trap handler, we must be recompiling for
// toggling debug mode on->off, in which case the old baseline script
// should have fully synced stack at every bytecode.
if (frameKind == ICEntry::Kind_NonOp) {
PCMappingSlotInfo slotInfo;
jsbytecode *pc = script->offsetToPC(pcOffset);
oldBaselineScript->nativeCodeForPC(script, pc, &slotInfo);
MOZ_ASSERT(slotInfo.numUnsynced() == 0);
}
DebugModeOSREntry(JSScript *script, BaselineDebugModeOSRInfo *info)
: script(script),
oldBaselineScript(script->baselineScript()),
oldStub(nullptr),
newStub(nullptr),
recompInfo(nullptr),
pcOffset(script->pcToOffset(info->pc)),
frameKind(info->frameKind)
{
#ifdef DEBUG
MOZ_ASSERT(pcOffset == script->pcToOffset(info->pc));
MOZ_ASSERT(frameKind == info->frameKind);
#endif
}
@ -99,7 +97,7 @@ struct DebugModeOSREntry
}
BaselineDebugModeOSRInfo *takeRecompInfo() {
MOZ_ASSERT(recompInfo);
MOZ_ASSERT(needsRecompileInfo() && recompInfo);
BaselineDebugModeOSRInfo *tmp = recompInfo;
recompInfo = nullptr;
return tmp;
@ -175,11 +173,24 @@ CollectOnStackScripts(JSContext *cx, const JitActivationIterator &activation,
switch (iter.type()) {
case JitFrame_BaselineJS: {
JSScript *script = iter.script();
uint8_t *retAddr = iter.returnAddressToFp();
ICEntry &entry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
if (!entries.append(DebugModeOSREntry(script, entry)))
return false;
if (BaselineDebugModeOSRInfo *info = iter.baselineFrame()->getDebugModeOSRInfo()) {
// If patching a previously patched yet unpopped frame, we can
// use the BaselineDebugModeOSRInfo on the frame directly to
// patch. Indeed, we cannot use iter.returnAddressToFp(), as
// it points into the debug mode OSR handler and cannot be
// used to look up a corresponding ICEntry.
//
// See cases F and G in PatchBaselineFrameForDebugMode.
if (!entries.append(DebugModeOSREntry(script, info)))
return false;
} else {
// Otherwise, use the return address to look up the ICEntry.
uint8_t *retAddr = iter.returnAddressToFp();
ICEntry &entry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
if (!entries.append(DebugModeOSREntry(script, entry)))
return false;
}
if (entries.back().needsRecompileInfo()) {
if (!entries.back().allocateRecompileInfo(cx))
@ -284,6 +295,13 @@ PatchBaselineFramesForDebugMode(JSContext *cx, const JitActivationIterator &acti
// D. From the debug prologue.
// E. From the debug epilogue.
//
// Off to On to Off:
// F. Undo case B above on previously patched yet unpopped frames.
//
// On to Off to On:
// G. Undo cases B, C, D, or E above on previously patched yet unpopped
// frames.
//
// In general, we patch the return address from the VM call to return to a
// "continuation fixer" to fix up machine state (registers and stack
// state). Specifics on what need to be done are documented below.
@ -291,7 +309,7 @@ PatchBaselineFramesForDebugMode(JSContext *cx, const JitActivationIterator &acti
IonCommonFrameLayout *prev = nullptr;
size_t entryIndex = *start;
DebugOnly<bool> expectedDebugMode = cx->compartment()->debugMode();
bool expectedDebugMode = cx->compartment()->debugMode();
for (JitFrameIterator iter(activation); !iter.done(); ++iter) {
DebugModeOSREntry &entry = entries[entryIndex];
@ -332,12 +350,33 @@ PatchBaselineFramesForDebugMode(JSContext *cx, const JitActivationIterator &acti
break;
}
bool popFrameReg;
// Cases F and G above.
//
// We undo a previous recompile by handling cases B, C, D, and E
// like normal, except that we retrieved the pc information via
// the previous OSR debug info stashed on the frame.
if (BaselineDebugModeOSRInfo *info = iter.baselineFrame()->getDebugModeOSRInfo()) {
MOZ_ASSERT(info->pc == pc);
MOZ_ASSERT(info->frameKind == kind);
// Case G, might need to undo B, C, D, or E.
MOZ_ASSERT_IF(expectedDebugMode, (kind == ICEntry::Kind_CallVM ||
kind == ICEntry::Kind_DebugTrap ||
kind == ICEntry::Kind_DebugPrologue ||
kind == ICEntry::Kind_DebugEpilogue));
// Case F, should only need to undo case B.
MOZ_ASSERT_IF(!expectedDebugMode, kind == ICEntry::Kind_CallVM);
// We will have allocated a new recompile info, so delete the
// existing one.
iter.baselineFrame()->deleteDebugModeOSRInfo();
}
// The RecompileInfo must already be allocated so that this
// function may be infallible.
BaselineDebugModeOSRInfo *recompInfo = entry.takeRecompInfo();
bool popFrameReg;
switch (kind) {
case ICEntry::Kind_CallVM:
// Case B above.

View File

@ -207,6 +207,16 @@ JitFrameIterator::script() const
return script;
}
uint8_t *
JitFrameIterator::resumeAddressToFp() const
{
// If we are settled on a patched BaselineFrame due to debug mode OSR, get
// the real return address via the stashed DebugModeOSRInfo.
if (isBaselineJS() && baselineFrame()->getDebugModeOSRInfo())
return baselineFrame()->debugModeOSRInfo()->resumeAddr;
return returnAddressToFp();
}
void
JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const
{
@ -214,7 +224,7 @@ JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes)
JSScript *script = this->script();
if (scriptRes)
*scriptRes = script;
uint8_t *retAddr = returnAddressToFp();
uint8_t *retAddr = resumeAddressToFp();
// If we have unwound the scope due to exception handling to a different
// pc, the frame should behave as if it were settled on that pc.
@ -223,11 +233,6 @@ JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes)
return;
}
// If we are in the middle of a recompile handler, get the real return
// address as stashed in the RecompileInfo.
if (BaselineDebugModeOSRInfo *info = baselineFrame()->getDebugModeOSRInfo())
retAddr = info->resumeAddr;
if (pcRes) {
// If the return address is into the prologue entry address or just
// after the debug prologue, then assume start of script.

View File

@ -191,6 +191,10 @@ class JitFrameIterator
return returnAddressToFp_;
}
// Returns the resume address. As above, except taking
// BaselineDebugModeOSRInfo into account, if present.
uint8_t *resumeAddressToFp() const;
// Previous frame information extracted from the current frame.
inline size_t prevFrameLocalSize() const;
inline FrameType prevType() const;

View File

@ -1491,8 +1491,8 @@ Simulator::setCallResult(int64_t res)
int
Simulator::readW(int32_t addr, SimInstruction *instr)
{
// The regexp engines emit unaligned loads, so we don't check for them here
// like the other methods below.
// The regexp engine emits unaligned loads, so we don't check for them here
// like most of the other methods do.
intptr_t *ptr = reinterpret_cast<intptr_t*>(addr);
return *ptr;
}
@ -1512,13 +1512,10 @@ Simulator::writeW(int32_t addr, int value, SimInstruction *instr)
uint16_t
Simulator::readHU(int32_t addr, SimInstruction *instr)
{
if ((addr & 1) == 0) {
uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr;
}
printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
return 0;
// The regexp engine emits unaligned loads, so we don't check for them here
// like most of the other methods do.
uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr;
}
int16_t

View File

@ -1764,7 +1764,7 @@ JS_GetClassPrototype(JSContext *cx, JSProtoKey key, JS::MutableHandle<JSObject*>
namespace JS {
/*
* Determine if the given object is an instance or prototype for a standard
* Determine if the given object is an instance/prototype/constructor for a standard
* class. If so, return the associated JSProtoKey. If not, return JSProto_Null.
*/
@ -1777,6 +1777,9 @@ IdentifyStandardPrototype(JSObject *obj);
extern JS_PUBLIC_API(JSProtoKey)
IdentifyStandardInstanceOrPrototype(JSObject *obj);
extern JS_PUBLIC_API(JSProtoKey)
IdentifyStandardConstructor(JSObject *obj);
} /* namespace JS */
extern JS_PUBLIC_API(JSProtoKey)

View File

@ -3439,6 +3439,26 @@ JS::IdentifyStandardInstanceOrPrototype(JSObject *obj)
return JSCLASS_CACHED_PROTO_KEY(obj->getClass());
}
JSProtoKey
JS::IdentifyStandardConstructor(JSObject *obj)
{
// Note that NATIVE_CTOR does not imply that we are a standard constructor,
// but the converse is true (at least until we start having self-hosted
// constructors for standard classes). This lets us avoid a costly loop for
// many functions (which, depending on the call site, may be the common case).
if (!obj->is<JSFunction>() || !(obj->as<JSFunction>().flags() & JSFunction::NATIVE_CTOR))
return JSProto_Null;
GlobalObject &global = obj->global();
for (size_t k = 0; k < JSProto_LIMIT; ++k) {
JSProtoKey key = static_cast<JSProtoKey>(k);
if (global.getConstructor(key) == ObjectValue(*obj))
return key;
}
return JSProto_Null;
}
bool
js::FindClassObject(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp)
{

View File

@ -2020,25 +2020,40 @@ class MOZ_STACK_CLASS StringRegExpGuard
*/
static const size_t MAX_FLAT_PAT_LEN = 256;
static JSAtom *
flattenPattern(JSContext *cx, JSAtom *patstr)
template <typename CharT>
static bool
flattenPattern(StringBuffer &sb, const CharT *chars, size_t len)
{
StringBuffer sb(cx);
if (!sb.reserve(patstr->length()))
return nullptr;
static const jschar ESCAPE_CHAR = '\\';
const jschar *chars = patstr->chars();
size_t len = patstr->length();
for (const jschar *it = chars; it != chars + len; ++it) {
static const char ESCAPE_CHAR = '\\';
for (const CharT *it = chars; it < chars + len; ++it) {
if (IsRegExpMetaChar(*it)) {
if (!sb.append(ESCAPE_CHAR) || !sb.append(*it))
return nullptr;
return false;
} else {
if (!sb.append(*it))
return nullptr;
return false;
}
}
return true;
}
static JSAtom *
flattenPattern(JSContext *cx, JSAtom *pat)
{
StringBuffer sb(cx);
if (!sb.reserve(pat->length()))
return nullptr;
if (pat->hasLatin1Chars()) {
AutoCheckCannotGC nogc;
if (!flattenPattern(sb, pat->latin1Chars(nogc), pat->length()))
return nullptr;
} else {
AutoCheckCannotGC nogc;
if (!flattenPattern(sb, pat->twoByteChars(nogc), pat->length()))
return nullptr;
}
return sb.finishAtom();
}
@ -2455,6 +2470,18 @@ class RopeBuilder {
namespace {
template <typename CharT>
static uint32_t
FindDollarIndex(const CharT *chars, size_t length)
{
if (const CharT *p = js_strchr_limit(chars, '$', chars + length)) {
uint32_t dollarIndex = p - chars;
MOZ_ASSERT(dollarIndex < length);
return dollarIndex;
}
return UINT32_MAX;
}
struct ReplaceData
{
explicit ReplaceData(JSContext *cx)
@ -2468,13 +2495,10 @@ struct ReplaceData
elembase = nullptr;
repstr = string;
const jschar *chars = repstr->chars();
if (const jschar *p = js_strchr_limit(chars, '$', chars + repstr->length())) {
dollarIndex = p - chars;
MOZ_ASSERT(dollarIndex < repstr->length());
} else {
dollarIndex = UINT32_MAX;
}
AutoCheckCannotGC nogc;
dollarIndex = string->hasLatin1Chars()
? FindDollarIndex(string->latin1Chars(nogc), string->length())
: FindDollarIndex(string->twoByteChars(nogc), string->length());
}
inline void setReplacementFunction(JSObject *func) {
@ -2550,8 +2574,9 @@ DoMatchForReplaceGlobal(JSContext *cx, RegExpStatics *res, HandleLinearString li
return true;
}
template <typename CharT>
static bool
InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
InterpretDollar(RegExpStatics *res, const CharT *bp, const CharT *dp, const CharT *ep,
ReplaceData &rdata, JSSubString *out, size_t *skip)
{
JS_ASSERT(*dp == '$');
@ -2568,7 +2593,7 @@ InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
if (num > res->getMatches().parenCount())
return false;
const jschar *cp = dp + 2;
const CharT *cp = dp + 2;
if (cp < ep && (dc = *cp, JS7_ISDEC(dc))) {
unsigned tmp = 10 * num + JS7_UNDEC(dc);
if (tmp <= res->getMatches().parenCount()) {
@ -2594,7 +2619,7 @@ InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
*skip = 2;
switch (dc) {
case '$':
out->init(rdata.repstr, dp - rdata.repstr->chars(), 1);
out->init(rdata.repstr, dp - bp, 1);
return true;
case '&':
res->getLastMatch(out);
@ -2612,6 +2637,45 @@ InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
return false;
}
template <typename CharT>
static bool
FindReplaceLengthString(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
{
JSLinearString *repstr = rdata.repstr;
CheckedInt<uint32_t> replen = repstr->length();
if (rdata.dollarIndex != UINT32_MAX) {
AutoCheckCannotGC nogc;
MOZ_ASSERT(rdata.dollarIndex < repstr->length());
const CharT *bp = repstr->chars<CharT>(nogc);
const CharT *dp = bp + rdata.dollarIndex;
const CharT *ep = bp + repstr->length();
do {
JSSubString sub;
size_t skip;
if (InterpretDollar(res, bp, dp, ep, rdata, &sub, &skip)) {
if (sub.length > skip)
replen += sub.length - skip;
else
replen -= skip - sub.length;
dp += skip;
} else {
dp++;
}
dp = js_strchr_limit(dp, '$', ep);
} while (dp);
}
if (!replen.isValid()) {
js_ReportAllocationOverflow(cx);
return false;
}
*sizep = replen.value();
return true;
}
static bool
FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
{
@ -2701,36 +2765,9 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
return true;
}
JSLinearString *repstr = rdata.repstr;
CheckedInt<uint32_t> replen = repstr->length();
if (rdata.dollarIndex != UINT32_MAX) {
MOZ_ASSERT(rdata.dollarIndex < repstr->length());
const jschar *dp = repstr->chars() + rdata.dollarIndex;
const jschar *ep = repstr->chars() + repstr->length();
do {
JSSubString sub;
size_t skip;
if (InterpretDollar(res, dp, ep, rdata, &sub, &skip)) {
if (sub.length > skip)
replen += sub.length - skip;
else
replen -= skip - sub.length;
dp += skip;
} else {
dp++;
}
dp = js_strchr_limit(dp, '$', ep);
} while (dp);
}
if (!replen.isValid()) {
js_ReportAllocationOverflow(cx);
return false;
}
*sizep = replen.value();
return true;
return rdata.repstr->hasLatin1Chars()
? FindReplaceLengthString<Latin1Char>(cx, res, rdata, sizep)
: FindReplaceLengthString<jschar>(cx, res, rdata, sizep);
}
/*
@ -2738,17 +2775,19 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
* derived from FindReplaceLength), and has been inflated to TwoByte if
* necessary.
*/
template <typename CharT>
static void
DoReplace(RegExpStatics *res, ReplaceData &rdata)
{
AutoCheckCannotGC nogc;
JSLinearString *repstr = rdata.repstr;
const jschar *bp = repstr->chars();
const jschar *cp = bp;
const CharT *bp = repstr->chars<CharT>(nogc);
const CharT *cp = bp;
if (rdata.dollarIndex != UINT32_MAX) {
MOZ_ASSERT(rdata.dollarIndex < repstr->length());
const jschar *dp = bp + rdata.dollarIndex;
const jschar *ep = bp + repstr->length();
const CharT *dp = bp + rdata.dollarIndex;
const CharT *ep = bp + repstr->length();
do {
/* Move one of the constant portions of the replacement value. */
size_t len = dp - cp;
@ -2757,7 +2796,7 @@ DoReplace(RegExpStatics *res, ReplaceData &rdata)
JSSubString sub;
size_t skip;
if (InterpretDollar(res, dp, ep, rdata, &sub, &skip)) {
if (InterpretDollar(res, bp, dp, ep, rdata, &sub, &skip)) {
rdata.sb.infallibleAppendSubstring(sub.base, sub.offset, sub.length);
cp += skip;
dp += skip;
@ -2810,10 +2849,12 @@ ReplaceRegExp(JSContext *cx, RegExpStatics *res, ReplaceData &rdata)
return false;
/* Append skipped-over portion of the search value. */
const jschar *left = str.chars() + leftoff;
rdata.sb.infallibleAppend(left, leftlen);
rdata.sb.infallibleAppendSubstring(&str, leftoff, leftlen);
DoReplace(res, rdata);
if (rdata.repstr->hasLatin1Chars())
DoReplace<Latin1Char>(res, rdata);
else
DoReplace<jschar>(res, rdata);
return true;
}
@ -2895,6 +2936,57 @@ BuildFlatReplacement(JSContext *cx, HandleString textstr, HandleString repstr,
return true;
}
template <typename CharT>
static bool
AppendDollarReplacement(StringBuffer &newReplaceChars, size_t firstDollarIndex,
const FlatMatch &fm, JSLinearString *text,
const CharT *repChars, size_t repLength)
{
JS_ASSERT(firstDollarIndex < repLength);
size_t matchStart = fm.match();
size_t matchLimit = matchStart + fm.patternLength();
/* Move the pre-dollar chunk in bulk. */
newReplaceChars.infallibleAppend(repChars, firstDollarIndex);
/* Move the rest char-by-char, interpreting dollars as we encounter them. */
const CharT *repLimit = repChars + repLength;
for (const CharT *it = repChars + firstDollarIndex; it < repLimit; ++it) {
if (*it != '$' || it == repLimit - 1) {
if (!newReplaceChars.append(*it))
return false;
continue;
}
switch (*(it + 1)) {
case '$': /* Eat one of the dollars. */
if (!newReplaceChars.append(*it))
return false;
break;
case '&':
if (!newReplaceChars.appendSubstring(text, matchStart, matchLimit - matchStart))
return false;
break;
case '`':
if (!newReplaceChars.appendSubstring(text, 0, matchStart))
return false;
break;
case '\'':
if (!newReplaceChars.appendSubstring(text, matchLimit, text->length() - matchLimit))
return false;
break;
default: /* The dollar we saw was not special (no matter what its mother told it). */
if (!newReplaceChars.append(*it))
return false;
continue;
}
++it; /* We always eat an extra char in the above switch. */
}
return true;
}
/*
* Perform a linear-scan dollar substitution on the replacement text,
* constructing a result string that looks like:
@ -2926,45 +3018,18 @@ BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *reps
if (!newReplaceChars.reserve(textstr->length() - fm.patternLength() + repstr->length()))
return false;
JS_ASSERT(firstDollarIndex < repstr->length());
/* Move the pre-dollar chunk in bulk. */
newReplaceChars.infallibleAppend(repstr->chars(), firstDollarIndex);
/* Move the rest char-by-char, interpreting dollars as we encounter them. */
const jschar *textchars = textstr->chars();
const jschar *repstrLimit = repstr->chars() + repstr->length();
for (const jschar *it = repstr->chars() + firstDollarIndex; it < repstrLimit; ++it) {
if (*it != '$' || it == repstrLimit - 1) {
if (!newReplaceChars.append(*it))
return false;
continue;
}
switch (*(it + 1)) {
case '$': /* Eat one of the dollars. */
if (!newReplaceChars.append(*it))
return false;
break;
case '&':
if (!newReplaceChars.append(textchars + matchStart, textchars + matchLimit))
return false;
break;
case '`':
if (!newReplaceChars.append(textchars, textchars + matchStart))
return false;
break;
case '\'':
if (!newReplaceChars.append(textchars + matchLimit, textchars + textstr->length()))
return false;
break;
default: /* The dollar we saw was not special (no matter what its mother told it). */
if (!newReplaceChars.append(*it))
return false;
continue;
}
++it; /* We always eat an extra char in the above switch. */
bool res;
if (repstr->hasLatin1Chars()) {
AutoCheckCannotGC nogc;
res = AppendDollarReplacement(newReplaceChars, firstDollarIndex, fm, textstr,
repstr->latin1Chars(nogc), repstr->length());
} else {
AutoCheckCannotGC nogc;
res = AppendDollarReplacement(newReplaceChars, firstDollarIndex, fm, textstr,
repstr->twoByteChars(nogc), repstr->length());
}
if (!res)
return false;
RootedString leftSide(cx, js_NewDependentString(cx, textstr, 0, matchStart));
if (!leftSide)
@ -2998,25 +3063,35 @@ struct StringRange
{ }
};
static inline JSFatInlineString *
FlattenSubstrings(JSContext *cx, const jschar *chars,
const StringRange *ranges, size_t rangesLen, size_t outputLen)
template <typename CharT>
static void
CopySubstringsToFatInline(JSFatInlineString *dest, const CharT *src, const StringRange *ranges,
size_t rangesLen, size_t outputLen)
{
JS_ASSERT(JSFatInlineString::twoByteLengthFits(outputLen));
CharT *buf = dest->init<CharT>(outputLen);
size_t pos = 0;
for (size_t i = 0; i < rangesLen; i++) {
PodCopy(buf + pos, src + ranges[i].start, ranges[i].length);
pos += ranges[i].length;
}
MOZ_ASSERT(pos == outputLen);
buf[outputLen] = 0;
}
static inline JSFatInlineString *
FlattenSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr, const StringRange *ranges,
size_t rangesLen, size_t outputLen)
{
JSFatInlineString *str = js_NewGCFatInlineString<CanGC>(cx);
if (!str)
return nullptr;
jschar *buf = str->initTwoByte(outputLen);
size_t pos = 0;
for (size_t i = 0; i < rangesLen; i++) {
PodCopy(buf + pos, chars + ranges[i].start, ranges[i].length);
pos += ranges[i].length;
}
JS_ASSERT(pos == outputLen);
buf[outputLen] = 0;
AutoCheckCannotGC nogc;
if (flatStr->hasLatin1Chars())
CopySubstringsToFatInline(str, flatStr->latin1Chars(nogc), ranges, rangesLen, outputLen);
else
CopySubstringsToFatInline(str, flatStr->twoByteChars(nogc), ranges, rangesLen, outputLen);
return str;
}
@ -3030,9 +3105,10 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
if (rangesLen == 1)
return js_NewDependentString(cx, flatStr, ranges[0].start, ranges[0].length);
const jschar *chars = flatStr->getChars(cx);
if (!chars)
return nullptr;
bool isLatin1 = flatStr->hasLatin1Chars();
uint32_t fatInlineMaxLength = isLatin1
? JSFatInlineString::MAX_LENGTH_LATIN1
: JSFatInlineString::MAX_LENGTH_TWO_BYTE;
/* Collect substrings into a rope */
size_t i = 0;
@ -3044,7 +3120,7 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
size_t substrLen = 0;
size_t end = i;
for (; end < rangesLen; end++) {
if (substrLen + ranges[end].length > JSFatInlineString::MAX_LENGTH_TWO_BYTE)
if (substrLen + ranges[end].length > fatInlineMaxLength)
break;
substrLen += ranges[end].length;
}
@ -3055,7 +3131,7 @@ AppendSubstrings(JSContext *cx, Handle<JSFlatString*> flatStr,
part = js_NewDependentString(cx, flatStr, sr.start, sr.length);
} else {
/* Copy the ranges (linearly) into a JSFatInlineString */
part = FlattenSubstrings(cx, chars, ranges + i, end - i, substrLen);
part = FlattenSubstrings(cx, flatStr, ranges + i, end - i, substrLen);
i = end;
}
@ -4623,17 +4699,24 @@ js_strdup(js::ThreadSafeContext *cx, const jschar *s)
return ret;
}
jschar *
js_strchr_limit(const jschar *s, jschar c, const jschar *limit)
template <typename CharT>
const CharT *
js_strchr_limit(const CharT *s, jschar c, const CharT *limit)
{
while (s < limit) {
if (*s == c)
return (jschar *)s;
return s;
s++;
}
return nullptr;
}
template const Latin1Char *
js_strchr_limit(const Latin1Char *s, jschar c, const Latin1Char *limit);
template const jschar *
js_strchr_limit(const jschar *s, jschar c, const jschar *limit);
jschar *
js::InflateString(ThreadSafeContext *cx, const char *bytes, size_t *lengthp)
{

View File

@ -231,8 +231,9 @@ js_strlen(const jschar *s);
extern int32_t
js_strcmp(const jschar *lhs, const jschar *rhs);
extern jschar *
js_strchr_limit(const jschar *s, jschar c, const jschar *limit);
template <typename CharT>
extern const CharT *
js_strchr_limit(const CharT *s, jschar c, const CharT *limit);
static MOZ_ALWAYS_INLINE void
js_strncpy(jschar *dst, const jschar *src, size_t nelem)

View File

@ -343,10 +343,6 @@ function jsTestDriverBrowserInit()
{
properties.version = '1.8';
}
else if (properties.test.match(/^ecma_6\/LexicalEnvironment/))
{
properties.version = '1.8';
}
}
// default to language=type;text/javascript. required for

View File

@ -1,5 +0,0 @@
// NOTE: This only turns on 1.8.5 in shell builds. The browser requires the
// futzing in js/src/tests/browser.js (which only turns on 1.8, the most
// the browser supports).
if (typeof version != 'undefined')
version(185);

View File

@ -1,18 +0,0 @@
// |reftest| fails-if(Function("try{Function('let\x20x=5;');return(1,eval)('let\x20x=3;\\'x\\'\x20in\x20this');}catch(e){return(true);}")()) -- needs bug 589199 fix (top-level let not same as var)
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
let v = "global-v";
function f(v, global)
{
with (global)
return v;
}
assertEq(f("argument-v", this), "argument-v");
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

View File

@ -28,6 +28,8 @@ using mozilla::DebugOnly;
using mozilla::Maybe;
using js::frontend::TokenStream;
using JS::AutoCheckCannotGC;
JS_STATIC_ASSERT(IgnoreCaseFlag == JSREG_FOLD);
JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB);
JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
@ -592,9 +594,20 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t *lastIndex
if (uint8_t *byteCode = maybeByteCode(input->hasLatin1Chars())) {
AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
const jschar *chars = input->chars() + charsOffset;
RegExpRunStatus result =
irregexp::InterpretCode(cx, byteCode, chars, start, length, &matches);
AutoStableStringChars inputChars(cx, input);
if (!inputChars.init())
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 jschar *chars = inputChars.twoByteRange().start().get() + charsOffset;
result = irregexp::InterpretCode(cx, byteCode, chars, start, length, &matches);
}
if (result == RegExpRunStatus_Success) {
matches.displace(displacement);
matches.checkAgainst(origLength);
@ -608,8 +621,14 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t *lastIndex
RegExpRunStatus result;
{
AutoTraceLog logJIT(logger, TraceLogger::IrregexpExecute);
const jschar *chars = input->chars() + charsOffset;
result = irregexp::ExecuteCode(cx, jitCodeTwoByte, chars, start, length, &matches);
AutoCheckCannotGC nogc;
if (input->hasLatin1Chars()) {
const Latin1Char *chars = input->latin1Chars(nogc) + charsOffset;
result = irregexp::ExecuteCode(cx, jitCodeLatin1, chars, start, length, &matches);
} else {
const jschar *chars = input->twoByteChars(nogc) + charsOffset;
result = irregexp::ExecuteCode(cx, jitCodeTwoByte, chars, start, length, &matches);
}
}
if (result == RegExpRunStatus_Error) {
@ -885,10 +904,10 @@ js::ParseRegExpFlags(JSContext *cx, JSString *flagStr, RegExpFlag *flagsOut)
bool ok;
jschar lastParsed;
if (linear->hasLatin1Chars()) {
JS::AutoCheckCannotGC nogc;
AutoCheckCannotGC nogc;
ok = ::ParseRegExpFlags(linear->latin1Chars(nogc), len, flagsOut, &lastParsed);
} else {
JS::AutoCheckCannotGC nogc;
AutoCheckCannotGC nogc;
ok = ::ParseRegExpFlags(linear->twoByteChars(nogc), len, flagsOut, &lastParsed);
}

View File

@ -255,7 +255,7 @@ inline void
StringBuffer::infallibleAppendSubstring(JSLinearString *base, size_t off, size_t len)
{
MOZ_ASSERT(off + len <= base->length());
MOZ_ASSERT(base->hasLatin1Chars() == isLatin1());
MOZ_ASSERT_IF(base->hasTwoByteChars(), isTwoByte());
JS::AutoCheckCannotGC nogc;
if (base->hasLatin1Chars())

View File

@ -80,8 +80,10 @@ const char* const XPCJSRuntime::mStrings[] = {
"__iterator__", // IDX_ITERATOR
"__exposedProps__", // IDX_EXPOSEDPROPS
"eval", // IDX_EVAL
"controllers", // IDX_CONTROLLERS
"controllers", // IDX_CONTROLLERS
"realFrameElement", // IDX_REALFRAMEELEMENT
"length", // IDX_LENGTH
"name", // IDX_NAME
};
/***************************************************************************/

View File

@ -480,6 +480,8 @@ public:
IDX_EVAL ,
IDX_CONTROLLERS ,
IDX_REALFRAMEELEMENT ,
IDX_LENGTH ,
IDX_NAME ,
IDX_TOTAL_COUNT // just a count of the above
};

View File

@ -29,8 +29,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=448587.xul
const Cu = Components.utils;
var sandbox = new Cu.Sandbox("about:blank");
var fwrapper = Cu.evalInSandbox("function f() {} f", sandbox);
is(fwrapper.prototype, Cu.evalInSandbox("f.prototype", sandbox),
"we don't censor .prototype through .wrappedJSObject");
is(Cu.unwaiveXrays(Cu.waiveXrays(fwrapper).prototype), Cu.evalInSandbox("f.prototype", sandbox),
".prototype visible through .wrappedJSObject");
is(fwrapper.prototype, undefined, ".prototype invisible through Xrays");
]]>
</script>
</window>

View File

@ -56,7 +56,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=812415
is(Cu.evalInSandbox('regFun.name', expanded), 'reg', "Expanded can see regular function's name");
checkThrows('expFun.name', regular, "Regular can't see expanded function's name");
Cu.evalInSandbox('regFun.expando = 30', expanded);
is(expanded.regFun.expando, 30, "Expanded can set expandos");
is(Cu.evalInSandbox('regFun.expando', expanded), 30, "Expanded can set expandos");
checkThrows('expFun.expando = 29', regular, "Regular can't set expandos");
// Check __proto__ stuff.

View File

@ -53,8 +53,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
"we end up with the appropriate constructor: " + c);
is(Cu.unwaiveXrays(Cu.waiveXrays(new iwin[c]).constructor), iwin[c],
"constructor property is set up right: " + c);
is(Object.getPrototypeOf(new iwin[c]),
Cu.unwaiveXrays(Cu.waiveXrays(iwin[c]).prototype),
is(Object.getPrototypeOf(new iwin[c]), iwin[c].prototype,
"prototype is correct: " + c);
is(global(new iwin[c]), iwin, "Got the right global: " + c);
}
@ -65,7 +64,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
is(global(num), iwin, "correct global for num");
var obj = new iwin.Object();
obj.foo = 2;
var withProto = iwin.Object.create(obj);
var withProto = Cu.unwaiveXrays(Cu.waiveXrays(iwin).Object.create(obj));
is(global(withProto), iwin, "correct global for withProto");
is(Cu.waiveXrays(withProto).foo, 2, "Inherits properly");
@ -85,6 +84,25 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
is(global(factoryFun), iwin, "proper global for factoryFun");
is(factoryFun().foo, 32, "factoryFun invokable");
is(global(factoryFun()), iwin, "minted objects live in the content scope");
testXray('Function', factoryFun, new iwin.Function(), ['caller', 'arguments', 'length', 'name']);
var echoThis = new iwin.Function('return this;');
echoThis.wrappedJSObject.bind = 42;
var boundEchoThis = echoThis.bind(document);
is(boundEchoThis(), document, "bind() works correctly over Xrays");
is(global(boundEchoThis), window, "bound functions live in the caller's scope");
ok(/return this/.test(echoThis.toSource()), 'toSource works: ' + echoThis.toSource());
ok(/return this/.test(echoThis.toString()), 'toString works: ' + echoThis.toString());
is(iwin.Function.prototype, Object.getPrototypeOf(echoThis), "Function.prototype works for standard classes");
is(echoThis.prototype, undefined, "Function.prototype not visible for non standard constructors");
iwin.eval('var foopyFunction = function namedFoopyFunction(a, b, c) {}');
var foopyFunction = Cu.unwaiveXrays(Cu.waiveXrays(iwin).foopyFunction);
ok(Cu.isXrayWrapper(foopyFunction), "Should be Xrays");
is(foopyFunction.name, "namedFoopyFunction", ".name works over Xrays");
is(foopyFunction.length, 3, ".length works over Xrays");
ok(Object.getOwnPropertyNames(foopyFunction).indexOf('length') >= 0, "Should list length");
ok(Object.getOwnPropertyNames(foopyFunction).indexOf('name') >= 0, "Should list name");
ok(Object.getOwnPropertyNames(foopyFunction).indexOf('prototype') == -1, "Should not list prototype");
ok(Object.getOwnPropertyNames(iwin.Array).indexOf('prototype') >= 0, "Should list prototype for standard constructor");
// Test interface objects that don't actually construct things.
is(iwin.Math.tan(4.5), Math.tan(4.5), "Math.tan works");
@ -164,6 +182,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
if (!isReleaseBuild)
gPrototypeProperties[c].push("move");
}
gPrototypeProperties['Function'] =
["constructor", "toSource", "toString", "apply", "call", "bind",
"isGenerator", "length", "name", "arguments", "caller"];
function filterOut(array, props) {
return array.filter(p => props.indexOf(p) == -1);
@ -242,7 +263,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
}
function testObject() {
testXray('Object', iwin.Object.create(new iwin.Object()), new iwin.Object(), []);
testXray('Object', Cu.unwaiveXrays(Cu.waiveXrays(iwin).Object.create(new iwin.Object())),
new iwin.Object(), []);
// Construct an object full of tricky things.
var trickyObject =

View File

@ -128,9 +128,9 @@ static bool
ForceCOWBehavior(JSObject *obj)
{
JSProtoKey key = IdentifyStandardInstanceOrPrototype(obj);
if (key == JSProto_Object || key == JSProto_Array) {
if (key == JSProto_Object || key == JSProto_Array || key == JSProto_Function) {
MOZ_ASSERT(GetXrayType(obj) == XrayForJSObject,
"We should use XrayWrappers for standard ES Object and Array "
"We should use XrayWrappers for standard ES Object, Array, and Function "
"instances modulo this hack");
return true;
}
@ -360,13 +360,6 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType,
if (!wantXrays || xrayType == NotXray) {
if (!securityWrapper)
return &CrossCompartmentWrapper::singleton;
// In general, we don't want opaque function wrappers to be callable.
// But in the case of XBL, we rely on content being able to invoke
// functions exposed from the XBL scope. We could remove this exception,
// if needed, by using ExportFunction to generate the content-side
// representations of XBL methods.
else if (originIsXBLScope)
return &FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>::singleton;
return &FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>::singleton;
}
@ -390,7 +383,15 @@ SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType,
CrossOriginAccessiblePropertiesOnly>::singleton;
// There's never any reason to expose pure JS objects to non-subsuming actors.
// Just use an opaque wrapper in this case.
//
// In general, we don't want opaque function wrappers to be callable.
// But in the case of XBL, we rely on content being able to invoke
// functions exposed from the XBL scope. We could remove this exception,
// if needed, by using ExportFunction to generate the content-side
// representations of XBL methods.
MOZ_ASSERT(xrayType == XrayForJSObject);
if (originIsXBLScope)
return &FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>::singleton;
return &FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>::singleton;
}

View File

@ -71,6 +71,7 @@ IsJSXraySupported(JSProtoKey key)
case JSProto_Date:
case JSProto_Object:
case JSProto_Array:
case JSProto_Function:
return true;
default:
return false;
@ -171,6 +172,8 @@ public:
class XrayTraits
{
public:
XrayTraits() {}
static JSObject* getTargetObject(JSObject *wrapper) {
return js::UncheckedUnwrap(wrapper, /* stopAtOuter = */ false);
}
@ -224,6 +227,9 @@ private:
JSObject* attachExpandoObject(JSContext *cx, HandleObject target,
nsIPrincipal *origin,
HandleObject exclusiveGlobal);
XrayTraits(XrayTraits &) MOZ_DELETE;
const XrayTraits& operator=(XrayTraits &) MOZ_DELETE;
};
class XPCWrappedNativeXrayTraits : public XrayTraits
@ -349,7 +355,11 @@ public:
static bool call(JSContext *cx, HandleObject wrapper,
const JS::CallArgs &args, js::Wrapper& baseInstance)
{
// We'll handle this when we start supporting Functions.
JSXrayTraits &self = JSXrayTraits::singleton;
RootedObject holder(cx, self.ensureHolder(cx, wrapper));
if (self.getProtoKey(holder) == JSProto_Function)
return baseInstance.call(cx, wrapper, args);
RootedValue v(cx, ObjectValue(*wrapper));
js_ReportIsNotFunction(cx, v);
return false;
@ -358,7 +368,11 @@ public:
static bool construct(JSContext *cx, HandleObject wrapper,
const JS::CallArgs &args, js::Wrapper& baseInstance)
{
// We'll handle this when we start supporting Functions.
JSXrayTraits &self = JSXrayTraits::singleton;
RootedObject holder(cx, self.ensureHolder(cx, wrapper));
if (self.getProtoKey(holder) == JSProto_Function)
return baseInstance.construct(cx, wrapper, args);
RootedValue v(cx, ObjectValue(*wrapper));
js_ReportIsNotFunction(cx, v);
return false;
@ -403,6 +417,7 @@ public:
enum {
SLOT_PROTOKEY = 0,
SLOT_ISPROTOTYPE,
SLOT_CONSTRUCTOR_FOR,
SLOT_COUNT
};
virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
@ -416,6 +431,11 @@ public:
return js::GetReservedSlot(holder, SLOT_ISPROTOTYPE).toBoolean();
}
static JSProtoKey constructorFor(JSObject *holder) {
int32_t key = js::GetReservedSlot(holder, SLOT_CONSTRUCTOR_FOR).toInt32();
return static_cast<JSProtoKey>(key);
}
static bool getOwnPropertyFromTargetIfSafe(JSContext *cx,
HandleObject target,
HandleObject wrapper,
@ -552,6 +572,32 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
"across origin boundaries, consider using Components.utils.cloneInto().");
return false;
}
} else if (key == JSProto_Function) {
if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_LENGTH)) {
FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY,
NumberValue(JS_GetFunctionArity(JS_GetObjectFunction(target))));
return true;
} else if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_NAME)) {
FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY,
StringValue(JS_GetFunctionId(JS_GetObjectFunction(target))));
} else if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE)) {
// Handle the 'prototype' property to make xrayedGlobal.StandardClass.prototype work.
JSProtoKey standardConstructor = constructorFor(holder);
if (standardConstructor != JSProto_Null) {
RootedObject standardProto(cx);
{
JSAutoCompartment ac(cx, target);
if (!JS_GetClassPrototype(cx, standardConstructor, &standardProto))
return false;
MOZ_ASSERT(standardProto);
}
if (!JS_WrapObject(cx, &standardProto))
return false;
FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY,
ObjectValue(*standardProto));
return true;
}
}
}
// The rest of this function applies only to prototypes.
@ -805,6 +851,16 @@ JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags
return false;
for (int32_t i = 0; i <= int32_t(length - 1); ++i)
props.infallibleAppend(INT_TO_JSID(i));
} else if (key == JSProto_Function) {
if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_LENGTH)))
return false;
if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_NAME)))
return false;
// Handle the .prototype property on standard constructors.
if (constructorFor(holder) != JSProto_Null) {
if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE)))
return false;
}
}
// The rest of this function applies only to prototypes.
@ -869,6 +925,13 @@ JSXrayTraits::createHolder(JSContext *cx, JSObject *wrapper)
v.setBoolean(isPrototype);
js::SetReservedSlot(holder, SLOT_ISPROTOTYPE, v);
// If this is a function, also compute whether it serves as a constructor
// for a standard class.
if (key == JSProto_Function) {
v.setNumber(static_cast<uint32_t>(IdentifyStandardConstructor(target)));
js::SetReservedSlot(holder, SLOT_CONSTRUCTOR_FOR, v);
}
return holder;
}

View File

@ -132,6 +132,7 @@ using namespace mozilla::system;
#include "mozilla/IMEStateManager.h"
#include "nsDocument.h"
#include "mozilla/dom/HTMLVideoElement.h"
#include "CameraPreferences.h"
using namespace mozilla;
using namespace mozilla::net;
@ -296,6 +297,8 @@ nsLayoutStatics::Initialize()
CounterStyleManager::InitializeBuiltinCounterStyles();
CameraPreferences::Initialize();
return NS_OK;
}
@ -426,4 +429,6 @@ nsLayoutStatics::Shutdown()
nsDocument::XPCOMShutdown();
CacheObserver::Shutdown();
CameraPreferences::Shutdown();
}

View File

@ -22,16 +22,19 @@ import mozlog
log = mozlog.getLogger('REFTEST')
class B2GDesktopReftest(RefTest):
def __init__(self, marionette):
marionette = None
def __init__(self, marionette_args):
RefTest.__init__(self)
self.last_test = os.path.basename(__file__)
self.marionette = marionette
self.marionette_args = marionette_args
self.profile = None
self.runner = None
self.test_script = os.path.join(here, 'b2g_start_script.js')
self.timeout = None
def run_marionette_script(self):
self.marionette = Marionette(**self.marionette_args)
assert(self.marionette.wait_for_port())
self.marionette.start_session()
self.marionette.set_context(self.marionette.CONTEXT_CHROME)
@ -71,8 +74,8 @@ class B2GDesktopReftest(RefTest):
cmdargs=args,
env=env,
process_class=ProcessHandler,
symbols_path=options.symbolsPath,
kp_kwargs=kp_kwargs)
process_args=kp_kwargs,
symbols_path=options.symbolsPath)
status = 0
try:
@ -151,14 +154,13 @@ class B2GDesktopReftest(RefTest):
def run_desktop_reftests(parser, options, args):
kwargs = {}
marionette_args = {}
if options.marionette:
host, port = options.marionette.split(':')
kwargs['host'] = host
kwargs['port'] = int(port)
marionette = Marionette.getMarionetteOrExit(**kwargs)
marionette_args['host'] = host
marionette_args['port'] = int(port)
reftest = B2GDesktopReftest(marionette)
reftest = B2GDesktopReftest(marionette_args)
options = ReftestOptions.verifyCommonOptions(parser, options, reftest)
if options == None:

View File

@ -201,7 +201,7 @@ class ReftestRunner(MozbuildObject):
raise Exception(ADB_NOT_FOUND % ('%s-remote' % suite, b2g_home))
options.b2gPath = b2g_home
options.logcat_dir = self.reftest_dir
options.logdir = self.reftest_dir
options.httpdPath = os.path.join(self.topsrcdir, 'netwerk', 'test', 'httpserver')
options.xrePath = xre_path
options.ignoreWindowSize = True
@ -335,9 +335,9 @@ def B2GCommand(func):
help='Path to busybox binary to install on device')
func = busybox(func)
logcatdir = CommandArgument('--logcat-dir', default=None,
help='directory to store logcat dump files')
func = logcatdir(func)
logdir = CommandArgument('--logdir', default=None,
help='directory to store log files')
func = logdir(func)
sdcard = CommandArgument('--sdcard', default="10MB",
help='Define size of sdcard: 1MB, 50MB...etc')

View File

@ -58,9 +58,9 @@ class B2GOptions(ReftestOptions):
defaults["noWindow"] = False
self.add_option("--adbpath", action="store",
type = "string", dest = "adbPath",
type = "string", dest = "adb_path",
help = "path to adb")
defaults["adbPath"] = "adb"
defaults["adb_path"] = "adb"
self.add_option("--deviceIP", action="store",
type = "string", dest = "deviceIP",
@ -101,10 +101,10 @@ class B2GOptions(ReftestOptions):
help="the path to a gecko distribution that should "
"be installed on the emulator prior to test")
defaults["geckoPath"] = None
self.add_option("--logcat-dir", action="store",
type="string", dest="logcat_dir",
help="directory to store logcat dump files")
defaults["logcat_dir"] = None
self.add_option("--logdir", action="store",
type="string", dest="logdir",
help="directory to store log files")
defaults["logdir"] = None
self.add_option('--busybox', action='store',
type='string', dest='busybox',
help="Path to busybox binary to install on device")
@ -166,8 +166,8 @@ class B2GOptions(ReftestOptions):
if options.geckoPath and not options.emulator:
self.error("You must specify --emulator if you specify --gecko-path")
if options.logcat_dir and not options.emulator:
self.error("You must specify --emulator if you specify --logcat-dir")
if options.logdir and not options.emulator:
self.error("You must specify --emulator if you specify --logdir")
#if not options.emulator and not options.deviceIP:
# print "ERROR: you must provide a device IP"
@ -497,8 +497,8 @@ def run_remote_reftests(parser, options, args):
kwargs['noWindow'] = True
if options.geckoPath:
kwargs['gecko_path'] = options.geckoPath
if options.logcat_dir:
kwargs['logcat_dir'] = options.logcat_dir
if options.logdir:
kwargs['logdir'] = options.logdir
if options.busybox:
kwargs['busybox'] = options.busybox
if options.symbolsPath:
@ -511,19 +511,21 @@ def run_remote_reftests(parser, options, args):
host,port = options.marionette.split(':')
kwargs['host'] = host
kwargs['port'] = int(port)
marionette = Marionette.getMarionetteOrExit(**kwargs)
if options.adb_path:
kwargs['adb_path'] = options.adb_path
marionette = Marionette(**kwargs)
auto.marionette = marionette
if options.emulator:
dm = marionette.emulator.dm
else:
# create the DeviceManager
kwargs = {'adbPath': options.adbPath,
kwargs = {'adbPath': options.adb_path,
'deviceRoot': options.remoteTestRoot}
if options.deviceIP:
kwargs.update({'host': options.deviceIP,
'port': options.devicePort})
dm = DeviagerADB(**kwargs)
dm = DeviceManagerADB(**kwargs)
auto.setDeviceManager(dm)
options = parser.verifyRemoteOptions(options, auto)

View File

@ -110,6 +110,7 @@ if CONFIG['_MSC_VER']:
'-wd4309', # '=' : truncation of constant value
'-wd4355', # 'this' : used in base member initializer list
'-wd4804', # '>' : unsafe use of type 'bool' in operation
'-wd4099', # mismatched class/struct tags
]
elif CONFIG['GNU_CXX']:
CFLAGS += [

View File

@ -137,8 +137,6 @@ namespace mozilla { namespace psm {
namespace {
NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)

View File

@ -20,6 +20,7 @@
#include "nsIProgrammingLanguage.h"
#include "nsIArray.h"
#include "nsComponentManagerUtils.h"
#include "nsReadableUtils.h"
#include "nsServiceManagerUtils.h"
#include "PSMRunnable.h"
@ -624,12 +625,21 @@ GetSubjectAltNames(CERTCertificate *nssCert,
nsAutoString name;
switch (current->type) {
case certDNSName:
name.AssignASCII((char*)current->name.other.data, current->name.other.len);
if (!allNames.IsEmpty()) {
allNames.AppendLiteral(", ");
{
nsDependentCSubstring nameFromCert(reinterpret_cast<char*>
(current->name.other.data),
current->name.other.len);
// dNSName fields are defined as type IA5String and thus should
// be limited to ASCII characters.
if (IsASCII(nameFromCert)) {
name.Assign(NS_ConvertASCIItoUTF16(nameFromCert));
if (!allNames.IsEmpty()) {
allNames.AppendLiteral(", ");
}
++nameCount;
allNames.Append(name);
}
}
++nameCount;
allNames.Append(name);
break;
case certIPAddress:
@ -709,8 +719,15 @@ AppendErrorTextMismatch(const nsString &host,
if (!useSAN) {
char *certName = CERT_GetCommonName(&nssCert->subject);
if (certName) {
++nameCount;
allNames.Assign(NS_ConvertUTF8toUTF16(certName));
nsDependentCSubstring commonName(certName, strlen(certName));
if (IsUTF8(commonName)) {
// Bug 1024781
// We should actually check that the common name is a valid dns name or
// ip address and not any string value before adding it to the display
// list.
++nameCount;
allNames.Assign(NS_ConvertUTF8toUTF16(commonName));
}
PORT_Free(certName);
}
}

View File

@ -67,9 +67,6 @@ const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = {
{ 0, }
};
static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
static PQGParams *
decode_pqg_params(char *aStr)
{

View File

@ -1542,6 +1542,10 @@ Daily counts are reported in the following properties:
translationOpportunityCount
Integer count of the number of opportunities there were to translate a page.
missedTranslationOpportunityCount
Integer count of the number of missed opportunities there were to translate a page.
A missed opportunity is when the page language is not supported by the translation
provider.
pageTranslatedCount
Integer count of the number of pages translated.
charactersTranslatedCount
@ -1559,6 +1563,9 @@ properties:
translationOpportunityCountsByLanguage
A mapping from language to count of opportunities to translate that
language.
missedTranslationOpportunityCountsByLanguage
A mapping from language to count of missed opportunities to translate that
language.
pageTranslatedCountsByLanguage
A mapping from language to the counts of pages translated from that
language. Each language entry will be an object containing a "total" member

View File

@ -5,7 +5,7 @@
config = {
"jsreftest_options": [
"--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--emulator=%(emulator)s",
"--emulator-res=800x1000", "--logcat-dir=%(logcat_dir)s",
"--emulator-res=800x1000", "--logdir=%(logcat_dir)s",
"--remote-webserver=%(remote_webserver)s", "--ignore-window-size",
"--xre-path=%(xre_path)s", "--symbols-path=%(symbols_path)s", "--busybox=%(busybox)s",
"--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
@ -15,7 +15,7 @@ config = {
"mochitest_options": [
"--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--console-level=INFO",
"--emulator=%(emulator)s", "--logcat-dir=%(logcat_dir)s",
"--emulator=%(emulator)s", "--logdir=%(logcat_dir)s",
"--remote-webserver=%(remote_webserver)s", "%(test_manifest)s",
"--xre-path=%(xre_path)s", "--symbols-path=%(symbols_path)s", "--busybox=%(busybox)s",
"--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
@ -25,7 +25,7 @@ config = {
"reftest_options": [
"--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--emulator=%(emulator)s",
"--emulator-res=800x1000", "--logcat-dir=%(logcat_dir)s",
"--emulator-res=800x1000", "--logdir=%(logcat_dir)s",
"--remote-webserver=%(remote_webserver)s", "--ignore-window-size",
"--xre-path=%(xre_path)s", "--symbols-path=%(symbols_path)s", "--busybox=%(busybox)s",
"--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s", "--enable-oop",
@ -34,7 +34,7 @@ config = {
"crashtest_options": [
"--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--emulator=%(emulator)s",
"--emulator-res=800x1000", "--logcat-dir=%(logcat_dir)s",
"--emulator-res=800x1000", "--logdir=%(logcat_dir)s",
"--remote-webserver=%(remote_webserver)s", "--ignore-window-size",
"--xre-path=%(xre_path)s", "--symbols-path=%(symbols_path)s", "--busybox=%(busybox)s",
"--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
@ -43,7 +43,7 @@ config = {
"xpcshell_options": [
"--adbpath=%(adbpath)s", "--b2gpath=%(b2gpath)s", "--emulator=%(emulator)s",
"--logcat-dir=%(logcat_dir)s", "--manifest=%(test_manifest)s", "--use-device-libs",
"--logdir=%(logcat_dir)s", "--manifest=%(test_manifest)s", "--use-device-libs",
"--testing-modules-dir=%(modules_dir)s", "--symbols-path=%(symbols_path)s",
"--busybox=%(busybox)s", "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
],

View File

@ -6,21 +6,49 @@ from gestures import smooth_scroll, pinch
from by import By
from marionette import Marionette, HTMLElement, Actions, MultiActions
from marionette_test import MarionetteTestCase, MarionetteJSTestCase, CommonTestCase, expectedFailure, skip, SkipTest
from emulator import Emulator
from errors import (
ErrorCodes, MarionetteException, InstallGeckoError, TimeoutException, InvalidResponseException,
JavascriptException, NoSuchElementException, XPathLookupException, NoSuchWindowException,
StaleElementException, ScriptTimeoutException, ElementNotVisibleException,
NoSuchFrameException, InvalidElementStateException, NoAlertPresentException,
InvalidCookieDomainException, UnableToSetCookieException, InvalidSelectorException,
MoveTargetOutOfBoundsException, FrameSendNotInitializedError, FrameSendFailureError
)
ElementNotVisibleException,
ErrorCodes,
FrameSendFailureError,
FrameSendNotInitializedError,
InvalidCookieDomainException,
InvalidElementStateException,
InvalidResponseException,
InvalidSelectorException,
JavascriptException,
MarionetteException,
MoveTargetOutOfBoundsException,
NoAlertPresentException,
NoSuchElementException,
NoSuchFrameException,
NoSuchWindowException,
ScriptTimeoutException,
StaleElementException,
TimeoutException,
UnableToSetCookieException,
XPathLookupException,
)
from runner import (
B2GTestCaseMixin, B2GTestResultMixin, BaseMarionetteOptions, BaseMarionetteTestRunner, EnduranceOptionsMixin,
EnduranceTestCaseMixin, HTMLReportingOptionsMixin, HTMLReportingTestResultMixin, HTMLReportingTestRunnerMixin,
Marionette, MarionetteTest, MarionetteTestResult, MarionetteTextTestRunner, MemoryEnduranceTestCaseMixin,
MozHttpd, OptionParser, TestManifest, TestResult, TestResultCollection
)
B2GTestCaseMixin,
B2GTestResultMixin,
BaseMarionetteOptions,
BaseMarionetteTestRunner,
EnduranceOptionsMixin,
EnduranceTestCaseMixin,
HTMLReportingOptionsMixin,
HTMLReportingTestResultMixin,
HTMLReportingTestRunnerMixin,
Marionette,
MarionetteTest,
MarionetteTestResult,
MarionetteTextTestRunner,
MemoryEnduranceTestCaseMixin,
MozHttpd,
OptionParser,
TestManifest,
TestResult,
TestResultCollection
)
from wait import Wait
from date_time_value import DateTimeValue
import decorators

View File

@ -1,98 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import platform
import subprocess
import sys
class B2GBuild(object):
@classmethod
def find_b2g_dir(cls):
for env_var in ('B2G_DIR', 'B2G_HOME'):
if env_var in os.environ:
env_dir = os.environ[env_var]
env_dir = cls.check_b2g_dir(env_dir)
if env_dir:
return env_dir
cwd = os.getcwd()
cwd = cls.check_b2g_dir(cwd)
if cwd:
return cwd
return None
@classmethod
def check_adb(cls, homedir):
if 'ADB' in os.environ:
env_adb = os.environ['ADB']
if os.path.exists(env_adb):
return env_adb
return cls.check_host_binary(homedir, 'adb')
@classmethod
def check_b2g_dir(cls, dir):
if os.path.isfile(os.path.join(dir, 'load-config.sh')):
return dir
oldstyle_dir = os.path.join(dir, 'glue', 'gonk-ics')
if os.access(oldstyle_dir, os.F_OK):
return oldstyle_dir
return None
@classmethod
def check_fastboot(cls, homedir):
return cls.check_host_binary(homedir, 'fastboot')
@classmethod
def check_host_binary(cls, homedir, binary):
host_dir = "linux-x86"
if platform.system() == "Darwin":
host_dir = "darwin-x86"
binary_path = subprocess.Popen(['which', binary],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
if binary_path.wait() == 0:
return binary_path.stdout.read().strip() # remove trailing newline
binary_paths = [os.path.join(homedir, 'glue', 'gonk', 'out', 'host',
host_dir, 'bin', binary),
os.path.join(homedir, 'out', 'host', host_dir,
'bin', binary),
os.path.join(homedir, 'bin', binary)]
for option in binary_paths:
if os.path.exists(option):
return option
raise Exception('%s not found!' % binary)
def __init__(self, homedir=None, emulator=False):
if not homedir:
homedir = self.find_b2g_dir()
else:
homedir = self.check_b2g_dir(homedir)
if not homedir:
raise EnvironmentError('Must define B2G_HOME or pass the homedir parameter')
self.homedir = homedir
self.adb_path = self.check_adb(self.homedir)
self.update_tools = os.path.join(self.homedir, 'tools', 'update-tools')
self.fastboot_path = None if emulator else self.check_fastboot(self.homedir)
def import_update_tools(self):
"""Import the update_tools package from B2G"""
sys.path.append(self.update_tools)
import update_tools
sys.path.pop()
return update_tools
def check_file(self, filePath):
if not os.access(filePath, os.F_OK):
raise Exception(('File not found: %s; did you pass the B2G home '
'directory as the homedir parameter, or set '
'B2G_HOME correctly?') % filePath)

View File

@ -1,70 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ConfigParser import ConfigParser
import posixpath
import shutil
import tempfile
import traceback
from b2gbuild import B2GBuild
from mozdevice import DeviceManagerADB
import mozcrash
class B2GInstance(B2GBuild):
def __init__(self, devicemanager=None, symbols_path=None, **kwargs):
B2GBuild.__init__(self, **kwargs)
self._dm = devicemanager
self._remote_profiles = None
self.symbols_path = symbols_path
@property
def dm(self):
if not self._dm:
self._dm = DeviceManagerADB(adbPath=self.adb_path)
return self._dm
@property
def remote_profiles(self):
if not self._remote_profiles:
self.check_remote_profiles()
return self._remote_profiles
def check_remote_profiles(self, remote_profiles_ini='/data/b2g/mozilla/profiles.ini'):
if not self.dm.fileExists(remote_profiles_ini):
raise Exception("Remote file '%s' not found" % remote_profiles_ini)
local_profiles_ini = tempfile.NamedTemporaryFile()
self.dm.getFile(remote_profiles_ini, local_profiles_ini.name)
cfg = ConfigParser()
cfg.read(local_profiles_ini.name)
remote_profiles = []
for section in cfg.sections():
if cfg.has_option(section, 'Path'):
if cfg.has_option(section, 'IsRelative') and cfg.getint(section, 'IsRelative'):
remote_profiles.append(posixpath.join(posixpath.dirname(remote_profiles_ini), cfg.get(section, 'Path')))
else:
remote_profiles.append(cfg.get(section, 'Path'))
self._remote_profiles = remote_profiles
return remote_profiles
def check_for_crashes(self):
remote_dump_dirs = [posixpath.join(p, 'minidumps') for p in self.remote_profiles]
crashed = False
for remote_dump_dir in remote_dump_dirs:
local_dump_dir = tempfile.mkdtemp()
self.dm.getDirectory(remote_dump_dir, local_dump_dir)
try:
if mozcrash.check_for_crashes(local_dump_dir, self.symbols_path):
crashed = True
except:
traceback.print_exc()
finally:
shutil.rmtree(local_dump_dir)
self.dm.removeDir(remote_dump_dir)
return crashed

View File

@ -1,539 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from b2ginstance import B2GInstance
import datetime
from mozdevice import devicemanagerADB, DMError
from mozprocess import ProcessHandlerMixin
import os
import re
import platform
import shutil
import socket
import subprocess
from telnetlib import Telnet
import tempfile
import time
import traceback
from emulator_battery import EmulatorBattery
from emulator_geo import EmulatorGeo
from emulator_screen import EmulatorScreen
from decorators import uses_marionette
from errors import (
InstallGeckoError,
InvalidResponseException,
MarionetteException,
ScriptTimeoutException,
TimeoutException
)
class LogOutputProc(ProcessHandlerMixin):
"""
Process handler for processes which save all output to a logfile.
If no logfile is specified, output will still be consumed to prevent
the output pipe's from overflowing.
"""
def __init__(self, cmd, logfile=None, **kwargs):
self.logfile = logfile
kwargs.setdefault('processOutputLine', []).append(self.log_output)
ProcessHandlerMixin.__init__(self, cmd, **kwargs)
def log_output(self, line):
if not self.logfile:
return
f = open(self.logfile, 'a')
f.write(line + "\n")
f.flush()
class Emulator(object):
deviceRe = re.compile(r"^emulator-(\d+)(\s*)(.*)$")
_default_res = '320x480'
prefs = {'app.update.enabled': False,
'app.update.staging.enabled': False,
'app.update.service.enabled': False}
env = {'MOZ_CRASHREPORTER': '1',
'MOZ_CRASHREPORTER_NO_REPORT': '1',
'MOZ_CRASHREPORTER_SHUTDOWN': '1'}
def __init__(self, homedir=None, noWindow=False, logcat_dir=None,
arch="x86", emulatorBinary=None, res=None, sdcard=None,
symbols_path=None, userdata=None):
self.port = None
self.dm = None
self._emulator_launched = False
self.proc = None
self.marionette_port = None
self.telnet = None
self._tmp_sdcard = None
self._tmp_userdata = None
self._adb_started = False
self.logcat_dir = logcat_dir
self.logcat_proc = None
self.arch = arch
self.binary = emulatorBinary
self.res = res or self._default_res
self.battery = EmulatorBattery(self)
self.geo = EmulatorGeo(self)
self.screen = EmulatorScreen(self)
self.homedir = homedir
self.sdcard = sdcard
self.symbols_path = symbols_path
self.noWindow = noWindow
if self.homedir is not None:
self.homedir = os.path.expanduser(homedir)
self.dataImg = userdata
self.copy_userdata = self.dataImg is None
def _check_for_b2g(self):
self.b2g = B2GInstance(homedir=self.homedir, emulator=True,
symbols_path=self.symbols_path)
self.adb = self.b2g.adb_path
self.homedir = self.b2g.homedir
if self.arch not in ("x86", "arm"):
raise Exception("Emulator architecture must be one of x86, arm, got: %s" %
self.arch)
host_dir = "linux-x86"
if platform.system() == "Darwin":
host_dir = "darwin-x86"
host_bin_dir = os.path.join("out", "host", host_dir, "bin")
if self.arch == "x86":
binary = os.path.join(host_bin_dir, "emulator-x86")
kernel = "prebuilts/qemu-kernel/x86/kernel-qemu"
sysdir = "out/target/product/generic_x86"
self.tail_args = []
else:
binary = os.path.join(host_bin_dir, "emulator")
kernel = "prebuilts/qemu-kernel/arm/kernel-qemu-armv7"
sysdir = "out/target/product/generic"
self.tail_args = ["-cpu", "cortex-a8"]
if(self.sdcard):
self.mksdcard = os.path.join(self.homedir, host_bin_dir, "mksdcard")
self.create_sdcard(self.sdcard)
if not self.binary:
self.binary = os.path.join(self.homedir, binary)
self.b2g.check_file(self.binary)
self.kernelImg = os.path.join(self.homedir, kernel)
self.b2g.check_file(self.kernelImg)
self.sysDir = os.path.join(self.homedir, sysdir)
self.b2g.check_file(self.sysDir)
if not self.dataImg:
self.dataImg = os.path.join(self.sysDir, 'userdata.img')
self.b2g.check_file(self.dataImg)
def __del__(self):
if self.telnet:
self.telnet.write('exit\n')
self.telnet.read_all()
@property
def args(self):
qemuArgs = [self.binary,
'-kernel', self.kernelImg,
'-sysdir', self.sysDir,
'-data', self.dataImg]
if self._tmp_sdcard:
qemuArgs.extend(['-sdcard', self._tmp_sdcard])
if self.noWindow:
qemuArgs.append('-no-window')
qemuArgs.extend(['-memory', '512',
'-partition-size', '512',
'-verbose',
'-skin', self.res,
'-gpu', 'on',
'-qemu'] + self.tail_args)
return qemuArgs
@property
def is_running(self):
if self._emulator_launched:
return self.proc is not None and self.proc.poll() is None
else:
return self.port is not None
def check_for_crash(self):
"""
Checks if the emulator has crashed or not. Always returns False if
we've connected to an already-running emulator, since we can't track
the emulator's pid in that case. Otherwise, returns True iff
self.proc is not None (meaning the emulator hasn't been explicitly
closed), and self.proc.poll() is also not None (meaning the emulator
process has terminated).
"""
return self._emulator_launched and self.proc is not None \
and self.proc.poll() is not None
def check_for_minidumps(self):
return self.b2g.check_for_crashes()
def create_sdcard(self, sdcard):
self._tmp_sdcard = tempfile.mktemp(prefix='sdcard')
sdargs = [self.mksdcard, "-l", "mySdCard", sdcard, self._tmp_sdcard]
sd = subprocess.Popen(sdargs, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
retcode = sd.wait()
if retcode:
raise Exception('unable to create sdcard : exit code %d: %s'
% (retcode, sd.stdout.read()))
return None
def _run_adb(self, args):
args.insert(0, self.adb)
if self.port:
args.insert(1, '-s')
args.insert(2, 'emulator-%d' % self.port)
adb = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
retcode = adb.wait()
if retcode:
raise Exception('adb terminated with exit code %d: %s'
% (retcode, adb.stdout.read()))
return adb.stdout.read()
def _get_telnet_response(self, command=None):
output = []
assert(self.telnet)
if command is not None:
self.telnet.write('%s\n' % command)
while True:
line = self.telnet.read_until('\n')
output.append(line.rstrip())
if line.startswith('OK'):
return output
elif line.startswith('KO:'):
raise Exception('bad telnet response: %s' % line)
def _run_telnet(self, command):
if not self.telnet:
self.telnet = Telnet('localhost', self.port)
self._get_telnet_response()
return self._get_telnet_response(command)
def _run_shell(self, args):
args.insert(0, 'shell')
return self._run_adb(args).split('\r\n')
def close(self):
if self.is_running and self._emulator_launched:
self.proc.kill()
if self._adb_started:
self._run_adb(['kill-server'])
self._adb_started = False
if self.proc:
retcode = self.proc.poll()
self.proc = None
if self._tmp_userdata:
os.remove(self._tmp_userdata)
self._tmp_userdata = None
if self._tmp_sdcard:
os.remove(self._tmp_sdcard)
self._tmp_sdcard = None
return retcode
if self.logcat_proc and self.logcat_proc.proc.poll() is None:
self.logcat_proc.kill()
return 0
def _get_adb_devices(self):
offline = set()
online = set()
output = self._run_adb(['devices'])
for line in output.split('\n'):
m = self.deviceRe.match(line)
if m:
if m.group(3) == 'offline':
offline.add(m.group(1))
else:
online.add(m.group(1))
return (online, offline)
def start_adb(self):
result = self._run_adb(['start-server'])
# We keep track of whether we've started adb or not, so we know
# if we need to kill it.
if 'daemon started successfully' in result:
self._adb_started = True
else:
self._adb_started = False
@uses_marionette
def wait_for_system_message(self, marionette):
marionette.set_script_timeout(45000)
# Telephony API's won't be available immediately upon emulator
# boot; we have to wait for the syste-message-listener-ready
# message before we'll be able to use them successfully. See
# bug 792647.
print 'waiting for system-message-listener-ready...'
try:
marionette.execute_async_script("""
waitFor(
function() { marionetteScriptFinished(true); },
function() { return isSystemMessageListenerReady(); }
);
""")
except ScriptTimeoutException:
print 'timed out'
# We silently ignore the timeout if it occurs, since
# isSystemMessageListenerReady() isn't available on
# older emulators. 45s *should* be enough of a delay
# to allow telephony API's to work.
pass
except (InvalidResponseException, IOError):
self.check_for_minidumps()
raise
print '...done'
def connect(self):
self.adb = B2GInstance.check_adb(self.homedir, emulator=True)
self.start_adb()
online, offline = self._get_adb_devices()
now = datetime.datetime.now()
while online == set([]):
time.sleep(1)
if datetime.datetime.now() - now > datetime.timedelta(seconds=60):
raise Exception('timed out waiting for emulator to be available')
online, offline = self._get_adb_devices()
self.port = int(list(online)[0])
self.dm = devicemanagerADB.DeviceManagerADB(adbPath=self.adb,
deviceSerial='emulator-%d' % self.port)
def start(self):
self._check_for_b2g()
self.start_adb()
qemu_args = self.args[:]
if self.copy_userdata:
# Make a copy of the userdata.img for this instance of the emulator to use.
self._tmp_userdata = tempfile.mktemp(prefix='marionette')
shutil.copyfile(self.dataImg, self._tmp_userdata)
qemu_args[qemu_args.index('-data') + 1] = self._tmp_userdata
original_online, original_offline = self._get_adb_devices()
filename = None
if self.logcat_dir:
filename = os.path.join(self.logcat_dir, 'qemu.log')
if os.path.isfile(filename):
self.rotate_log(filename)
self.proc = LogOutputProc(qemu_args, filename)
self.proc.run()
online, offline = self._get_adb_devices()
now = datetime.datetime.now()
while online - original_online == set([]):
time.sleep(1)
if datetime.datetime.now() - now > datetime.timedelta(seconds=60):
raise TimeoutException('timed out waiting for emulator to start')
online, offline = self._get_adb_devices()
self.port = int(list(online - original_online)[0])
self._emulator_launched = True
self.dm = devicemanagerADB.DeviceManagerADB(adbPath=self.adb,
deviceSerial='emulator-%d' % self.port)
# bug 802877
time.sleep(10)
self.geo.set_default_location()
self.screen.initialize()
if self.logcat_dir:
self.save_logcat()
# setup DNS fix for networking
self._run_adb(['shell', 'setprop', 'net.dns1', '10.0.2.3'])
@uses_marionette
def wait_for_homescreen(self, marionette):
print 'waiting for homescreen...'
marionette.set_context(marionette.CONTEXT_CONTENT)
marionette.execute_async_script("""
log('waiting for mozbrowserloadend');
window.addEventListener('mozbrowserloadend', function loaded(aEvent) {
log('received mozbrowserloadend for ' + aEvent.target.src);
if (aEvent.target.src.indexOf('ftu') != -1 || aEvent.target.src.indexOf('homescreen') != -1) {
window.removeEventListener('mozbrowserloadend', loaded);
marionetteScriptFinished();
}
});""", script_timeout=120000)
print '...done'
def setup(self, marionette, gecko_path=None, busybox=None):
self.set_environment(marionette)
if busybox:
self.install_busybox(busybox)
if gecko_path:
self.install_gecko(gecko_path, marionette)
self.wait_for_system_message(marionette)
self.set_prefs(marionette)
@uses_marionette
def set_environment(self, marionette):
for k, v in self.env.iteritems():
marionette.execute_script("""
let env = Cc["@mozilla.org/process/environment;1"].
getService(Ci.nsIEnvironment);
env.set("%s", "%s");
""" % (k, v))
@uses_marionette
def set_prefs(self, marionette):
for pref in self.prefs:
marionette.execute_script("""
Components.utils.import("resource://gre/modules/Services.jsm");
let argtype = typeof(arguments[1]);
switch(argtype) {
case 'boolean':
Services.prefs.setBoolPref(arguments[0], arguments[1]);
break;
case 'number':
Services.prefs.setIntPref(arguments[0], arguments[1]);
break;
default:
Services.prefs.setCharPref(arguments[0], arguments[1]);
}
""", [pref, self.prefs[pref]])
def restart_b2g(self):
print 'restarting B2G'
self.dm.shellCheckOutput(['stop', 'b2g'])
time.sleep(10)
self.dm.shellCheckOutput(['start', 'b2g'])
if not self.wait_for_port():
raise TimeoutException("Timeout waiting for marionette on port '%s'" % self.marionette_port)
def install_gecko(self, gecko_path, marionette):
"""
Install gecko into the emulator using adb push. Restart b2g after the
installation.
"""
# See bug 800102. We use this particular method of installing
# gecko in order to avoid an adb bug in which adb will sometimes
# hang indefinitely while copying large files to the system
# partition.
print 'installing gecko binaries...'
# see bug 809437 for the path that lead to this madness
try:
# need to remount so we can write to /system/b2g
self._run_adb(['remount'])
self.dm.removeDir('/data/local/b2g')
self.dm.mkDir('/data/local/b2g')
self.dm.pushDir(gecko_path, '/data/local/b2g', retryLimit=10)
self.dm.shellCheckOutput(['stop', 'b2g'])
for root, dirs, files in os.walk(gecko_path):
for filename in files:
rel_path = os.path.relpath(os.path.join(root, filename), gecko_path)
data_local_file = os.path.join('/data/local/b2g', rel_path)
system_b2g_file = os.path.join('/system/b2g', rel_path)
print 'copying', data_local_file, 'to', system_b2g_file
self.dm.shellCheckOutput(['dd',
'if=%s' % data_local_file,
'of=%s' % system_b2g_file])
self.restart_b2g()
except (DMError, MarionetteException):
# Bug 812395 - raise a single exception type for these so we can
# explicitly catch them elsewhere.
# print exception, but hide from mozharness error detection
exc = traceback.format_exc()
exc = exc.replace('Traceback', '_traceback')
print exc
raise InstallGeckoError("unable to restart B2G after installing gecko")
def install_busybox(self, busybox):
self._run_adb(['remount'])
remote_file = "/system/bin/busybox"
print 'pushing %s' % remote_file
self.dm.pushFile(busybox, remote_file, retryLimit=10)
self._run_adb(['shell', 'cd /system/bin; chmod 555 busybox; for x in `./busybox --list`; do ln -s ./busybox $x; done'])
self.dm._verifyZip()
def rotate_log(self, srclog, index=1):
""" Rotate a logfile, by recursively rotating logs further in the sequence,
deleting the last file if necessary.
"""
basename = os.path.basename(srclog)
basename = basename[:-len('.log')]
if index > 1:
basename = basename[:-len('.1')]
basename = '%s.%d.log' % (basename, index)
destlog = os.path.join(self.logcat_dir, basename)
if os.path.isfile(destlog):
if index == 3:
os.remove(destlog)
else:
self.rotate_log(destlog, index+1)
shutil.move(srclog, destlog)
def save_logcat(self):
""" Save the output of logcat to a file.
"""
filename = os.path.join(self.logcat_dir, "emulator-%d.log" % self.port)
if os.path.isfile(filename):
self.rotate_log(filename)
cmd = [self.adb, '-s', 'emulator-%d' % self.port, 'logcat', '-v', 'threadtime']
self.logcat_proc = LogOutputProc(cmd, filename)
self.logcat_proc.run()
def setup_port_forwarding(self, remote_port):
""" Set up TCP port forwarding to the specified port on the device,
using any availble local port, and return the local port.
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("",0))
local_port = s.getsockname()[1]
s.close()
self._run_adb(['forward',
'tcp:%d' % local_port,
'tcp:%d' % remote_port])
self.marionette_port = local_port
return local_port
def wait_for_port(self, timeout=300):
assert(self.marionette_port)
starttime = datetime.datetime.now()
while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', self.marionette_port))
data = sock.recv(16)
sock.close()
if ':' in data:
return True
except:
import traceback
print traceback.format_exc()
time.sleep(1)
return False

View File

@ -25,21 +25,20 @@ class GeckoInstance(object):
self.marionette_host = host
self.marionette_port = port
self.bin = bin
self.profile = profile
self.profile_path = profile
self.app_args = app_args or []
self.runner = None
self.symbols_path = symbols_path
self.gecko_log = gecko_log
def start(self):
profile_path = self.profile
profile_args = {"preferences": self.required_prefs}
if not profile_path:
runner_class = Runner
if not self.profile_path:
profile_args["restore"] = False
profile = Profile(**profile_args)
else:
runner_class = CloneRunner
profile_args["path_from"] = profile_path
profile_args["path_from"] = self.profile_path
profile = Profile.clone(**profile_args)
if self.gecko_log is None:
self.gecko_log = 'gecko.log'
@ -57,13 +56,13 @@ class GeckoInstance(object):
# https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting
env.update({ 'MOZ_CRASHREPORTER': '1',
'MOZ_CRASHREPORTER_NO_REPORT': '1', })
self.runner = runner_class.create(
self.runner = Runner(
binary=self.bin,
profile_args=profile_args,
profile=profile,
cmdargs=['-no-remote', '-marionette'] + self.app_args,
env=env,
symbols_path=self.symbols_path,
kp_kwargs={
process_args={
'processOutputLine': [NullOutput()],
'logfile': self.gecko_log})
self.runner.start()
@ -72,24 +71,19 @@ class GeckoInstance(object):
return self.runner.check_for_crashes()
def close(self):
self.runner.stop()
self.runner.cleanup()
if self.runner:
self.runner.stop()
self.runner.cleanup()
class B2GDesktopInstance(GeckoInstance):
required_prefs = {"focusmanager.testmode": True}
apps = {'b2g': B2GDesktopInstance,
'b2gdesktop': B2GDesktopInstance}
class CloneRunner(Runner):
profile_class = Profile.clone
class NullOutput(object):
def __call__(self, line):
pass
apps = {'b2g': B2GDesktopInstance,
'b2gdesktop': B2GDesktopInstance}

View File

@ -6,27 +6,20 @@ import ConfigParser
import datetime
import os
import socket
import sys
import StringIO
import time
import traceback
import base64
from application_cache import ApplicationCache
from decorators import do_crash_check
from emulator import Emulator
from emulator_screen import EmulatorScreen
from errors import (
ErrorCodes, MarionetteException, InstallGeckoError, TimeoutException, InvalidResponseException,
JavascriptException, NoSuchElementException, XPathLookupException, NoSuchWindowException,
StaleElementException, ScriptTimeoutException, ElementNotVisibleException,
NoSuchFrameException, InvalidElementStateException, NoAlertPresentException,
InvalidCookieDomainException, UnableToSetCookieException, InvalidSelectorException,
MoveTargetOutOfBoundsException, FrameSendNotInitializedError, FrameSendFailureError
)
from keys import Keys
from marionette_transport import MarionetteTransport
from mozrunner import B2GEmulatorRunner
import geckoinstance
import errors
class HTMLElement(object):
"""
@ -451,32 +444,24 @@ class Marionette(object):
TIMEOUT_SEARCH = 'implicit'
TIMEOUT_SCRIPT = 'script'
TIMEOUT_PAGE = 'page load'
SCREEN_ORIENTATIONS = {"portrait": EmulatorScreen.SO_PORTRAIT_PRIMARY,
"landscape": EmulatorScreen.SO_LANDSCAPE_PRIMARY,
"portrait-primary": EmulatorScreen.SO_PORTRAIT_PRIMARY,
"landscape-primary": EmulatorScreen.SO_LANDSCAPE_PRIMARY,
"portrait-secondary": EmulatorScreen.SO_PORTRAIT_SECONDARY,
"landscape-secondary": EmulatorScreen.SO_LANDSCAPE_SECONDARY}
def __init__(self, host='localhost', port=2828, app=None, app_args=None, bin=None,
profile=None, emulator=None, sdcard=None, emulatorBinary=None,
emulatorImg=None, emulator_res=None, gecko_path=None,
connectToRunningEmulator=False, homedir=None, baseurl=None,
noWindow=False, logcat_dir=None, busybox=None, symbols_path=None,
timeout=None, device_serial=None, gecko_log=None):
profile=None, emulator=None, sdcard=None, emulator_img=None,
emulator_binary=None, emulator_res=None, connect_to_running_emulator=False,
gecko_log=None, homedir=None, baseurl=None, no_window=False, logdir=None,
busybox=None, symbols_path=None, timeout=None, device_serial=None,
adb_path=None):
self.host = host
self.port = self.local_port = port
self.bin = bin
self.instance = None
self.profile = profile
self.session = None
self.window = None
self.runner = None
self.emulator = None
self.extra_emulators = []
self.homedir = homedir
self.baseurl = baseurl
self.noWindow = noWindow
self.logcat_dir = logcat_dir
self.no_window = no_window
self._test_name = None
self.timeout = timeout
self.device_serial = device_serial
@ -485,7 +470,7 @@ class Marionette(object):
port = int(self.port)
if not Marionette.is_port_available(port, host=self.host):
ex_msg = "%s:%d is unavailable." % (self.host, port)
raise MarionetteException(message=ex_msg)
raise errors.MarionetteException(message=ex_msg)
if app:
# select instance class for the given app
try:
@ -504,52 +489,56 @@ class Marionette(object):
KeyError):
instance_class = geckoinstance.GeckoInstance
self.instance = instance_class(host=self.host, port=self.port,
bin=self.bin, profile=self.profile,
bin=self.bin, profile=profile,
app_args=app_args, symbols_path=symbols_path,
gecko_log=gecko_log)
self.instance.start()
assert(self.wait_for_port()), "Timed out waiting for port!"
if emulator:
self.emulator = Emulator(homedir=homedir,
noWindow=self.noWindow,
logcat_dir=self.logcat_dir,
arch=emulator,
sdcard=sdcard,
symbols_path=symbols_path,
emulatorBinary=emulatorBinary,
userdata=emulatorImg,
res=emulator_res)
self.runner = B2GEmulatorRunner(b2g_home=homedir,
no_window=self.no_window,
logdir=logdir,
arch=emulator,
sdcard=sdcard,
symbols_path=symbols_path,
binary=emulator_binary,
userdata=emulator_img,
resolution=emulator_res,
profile=profile,
adb_path=adb_path)
self.emulator = self.runner.device
self.emulator.start()
self.port = self.emulator.setup_port_forwarding(self.port)
assert(self.emulator.wait_for_port()), "Timed out waiting for port!"
assert(self.emulator.wait_for_port(self.port)), "Timed out waiting for port!"
if connectToRunningEmulator:
self.emulator = Emulator(homedir=homedir,
logcat_dir=self.logcat_dir)
if connect_to_running_emulator:
self.runner = B2GEmulatorRunner(b2g_home=homedir,
logdir=logdir)
self.emulator = self.runner.device
self.emulator.connect()
self.port = self.emulator.setup_port_forwarding(self.port)
assert(self.emulator.wait_for_port()), "Timed out waiting for port!"
assert(self.emulator.wait_for_port(self.port)), "Timed out waiting for port!"
self.client = MarionetteTransport(self.host, self.port)
if emulator:
self.emulator.setup(self,
gecko_path=gecko_path,
busybox=busybox)
if busybox:
self.emulator.install_busybox(busybox=busybox)
self.emulator.wait_for_system_message(self)
def cleanup(self):
if self.session:
try:
self.delete_session()
except (MarionetteException, socket.error, IOError):
except (errors.MarionetteException, socket.error, IOError):
# These exceptions get thrown if the Marionette server
# hit an exception/died or the connection died. We can
# do no further server-side cleanup in this case.
pass
self.session = None
if self.emulator:
self.emulator.close()
if self.runner:
self.runner.cleanup()
if self.instance:
self.instance.close()
for qemu in self.extra_emulators:
@ -570,26 +559,6 @@ class Marionette(object):
finally:
s.close()
@classmethod
def getMarionetteOrExit(cls, *args, **kwargs):
try:
m = cls(*args, **kwargs)
return m
except InstallGeckoError:
# Bug 812395 - the process of installing gecko into the emulator
# and then restarting B2G tickles some bug in the emulator/b2g
# that intermittently causes B2G to fail to restart. To work
# around this in TBPL runs, we will fail gracefully from this
# error so that the mozharness script can try the run again.
# This string will get caught by mozharness and will cause it
# to retry the tests.
print "Error installing gecko!"
# Exit without a normal exception to prevent mozharness from
# flagging the error.
sys.exit()
def wait_for_port(self, timeout=60):
starttime = datetime.datetime.now()
while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
@ -609,7 +578,7 @@ class Marionette(object):
@do_crash_check
def _send_message(self, command, response_key="ok", **kwargs):
if not self.session and command != "newSession":
raise MarionetteException("Please start a session")
raise errors.MarionetteException("Please start a session")
message = {"name": command}
if self.session:
@ -623,8 +592,8 @@ class Marionette(object):
self.session = None
self.window = None
self.client.close()
raise TimeoutException(
"Connection timed out", status=ErrorCodes.TIMEOUT)
raise errors.TimeoutException(
"Connection timed out", status=errors.ErrorCodes.TIMEOUT)
# Process any emulator commands that are sent from a script
# while it's executing.
@ -646,7 +615,7 @@ class Marionette(object):
def _handle_emulator_cmd(self, response):
cmd = response.get("emulator_cmd")
if not cmd or not self.emulator:
raise MarionetteException(
raise errors.MarionetteException(
"No emulator in this test to run command against")
cmd = cmd.encode("ascii")
result = self.emulator._run_telnet(cmd)
@ -657,9 +626,12 @@ class Marionette(object):
def _handle_emulator_shell(self, response):
args = response.get("emulator_shell")
if not isinstance(args, list) or not self.emulator:
raise MarionetteException(
raise errors.MarionetteException(
"No emulator in this test to run shell command against")
result = self.emulator._run_shell(args)
buf = StringIO.StringIO()
self.emulator.dm.shell(args, buf)
result = str(buf.getvalue()[0:-1]).rstrip().splitlines()
buf.close()
return self.client.send({"name": "emulatorCmdResult",
"id": response.get("id"),
"result": result})
@ -671,62 +643,59 @@ class Marionette(object):
stacktrace = response['error'].get('stacktrace')
# status numbers come from
# http://code.google.com/p/selenium/wiki/JsonWireProtocol#Response_Status_Codes
if status == ErrorCodes.NO_SUCH_ELEMENT:
raise NoSuchElementException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.NO_SUCH_FRAME:
raise NoSuchFrameException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.STALE_ELEMENT_REFERENCE:
raise StaleElementException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.ELEMENT_NOT_VISIBLE:
raise ElementNotVisibleException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.INVALID_ELEMENT_STATE:
raise InvalidElementStateException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.UNKNOWN_ERROR:
raise MarionetteException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.ELEMENT_IS_NOT_SELECTABLE:
raise ElementNotSelectableException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.JAVASCRIPT_ERROR:
raise JavascriptException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.XPATH_LOOKUP_ERROR:
raise XPathLookupException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.TIMEOUT:
raise TimeoutException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.NO_SUCH_WINDOW:
raise NoSuchWindowException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.INVALID_COOKIE_DOMAIN:
raise InvalidCookieDomainException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.UNABLE_TO_SET_COOKIE:
raise UnableToSetCookieException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.NO_ALERT_OPEN:
raise NoAlertPresentException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.SCRIPT_TIMEOUT:
raise ScriptTimeoutException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.INVALID_SELECTOR \
or status == ErrorCodes.INVALID_XPATH_SELECTOR \
or status == ErrorCodes.INVALID_XPATH_SELECTOR_RETURN_TYPER:
raise InvalidSelectorException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.MOVE_TARGET_OUT_OF_BOUNDS:
raise MoveTargetOutOfBoundsException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.FRAME_SEND_NOT_INITIALIZED_ERROR:
raise FrameSendNotInitializedError(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.FRAME_SEND_FAILURE_ERROR:
raise FrameSendFailureError(message=message, status=status, stacktrace=stacktrace)
if status == errors.ErrorCodes.NO_SUCH_ELEMENT:
raise errors.NoSuchElementException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.NO_SUCH_FRAME:
raise errors.NoSuchFrameException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.STALE_ELEMENT_REFERENCE:
raise errors.StaleElementException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.ELEMENT_NOT_VISIBLE:
raise errors.ElementNotVisibleException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.INVALID_ELEMENT_STATE:
raise errors.InvalidElementStateException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.UNKNOWN_ERROR:
raise errors.MarionetteException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.ELEMENT_IS_NOT_SELECTABLE:
raise errors.ElementNotSelectableException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.JAVASCRIPT_ERROR:
raise errors.JavascriptException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.XPATH_LOOKUP_ERROR:
raise errors.XPathLookupException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.TIMEOUT:
raise errors.TimeoutException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.NO_SUCH_WINDOW:
raise errors.NoSuchWindowException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.INVALID_COOKIE_DOMAIN:
raise errors.InvalidCookieDomainException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.UNABLE_TO_SET_COOKIE:
raise errors.UnableToSetCookieException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.NO_ALERT_OPEN:
raise errors.NoAlertPresentException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.SCRIPT_TIMEOUT:
raise errors.ScriptTimeoutException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.INVALID_SELECTOR \
or status == errors.ErrorCodes.INVALID_XPATH_SELECTOR \
or status == errors.ErrorCodes.INVALID_XPATH_SELECTOR_RETURN_TYPER:
raise errors.InvalidSelectorException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.MOVE_TARGET_OUT_OF_BOUNDS:
raise errors.MoveTargetOutOfBoundsException(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.FRAME_SEND_NOT_INITIALIZED_ERROR:
raise errors.FrameSendNotInitializedError(message=message, status=status, stacktrace=stacktrace)
elif status == errors.ErrorCodes.FRAME_SEND_FAILURE_ERROR:
raise errors.FrameSendFailureError(message=message, status=status, stacktrace=stacktrace)
else:
raise MarionetteException(message=message, status=status, stacktrace=stacktrace)
raise MarionetteException(message=response, status=500)
raise errors.MarionetteException(message=message, status=status, stacktrace=stacktrace)
raise errors.MarionetteException(message=response, status=500)
def check_for_crash(self):
returncode = None
name = None
crashed = False
if self.emulator:
if self.emulator.check_for_crash():
if self.runner:
if self.runner.check_for_crashes():
returncode = self.emulator.proc.returncode
name = 'emulator'
crashed = True
if self.emulator.check_for_minidumps():
crashed = True
elif self.instance:
if self.instance.check_for_crashes():
crashed = True
@ -1459,4 +1428,4 @@ class Marionette(object):
"""
self._send_message("setScreenOrientation", "ok", orientation=orientation)
if self.emulator:
self.emulator.screen.orientation = self.SCREEN_ORIENTATIONS[orientation.lower()]
self.emulator.screen.orientation = orientation.lower()

View File

@ -367,11 +367,11 @@ class BaseMarionetteOptions(OptionParser):
'specify which architecture to emulate for both cases')
self.add_option('--emulator-binary',
action='store',
dest='emulatorBinary',
dest='emulator_binary',
help='launch a specific emulator binary rather than launching from the B2G built emulator')
self.add_option('--emulator-img',
action='store',
dest='emulatorImg',
dest='emulator_img',
help='use a specific image file instead of a fresh one')
self.add_option('--emulator-res',
action='store',
@ -385,11 +385,11 @@ class BaseMarionetteOptions(OptionParser):
help='size of sdcard to create for the emulator')
self.add_option('--no-window',
action='store_true',
dest='noWindow',
dest='no_window',
default=False,
help='when Marionette launches an emulator, start it with the -no-window argument')
self.add_option('--logcat-dir',
dest='logcat_dir',
dest='logdir',
action='store',
help='directory to store logcat dump files')
self.add_option('--address',
@ -441,10 +441,6 @@ class BaseMarionetteOptions(OptionParser):
action='store',
dest='xml_output',
help='xml output')
self.add_option('--gecko-path',
dest='gecko_path',
action='store',
help='path to b2g gecko binaries that should be installed on the device or emulator')
self.add_option('--testvars',
dest='testvars',
action='store',
@ -525,8 +521,8 @@ class BaseMarionetteOptions(OptionParser):
'elasticsearch-zlb.webapp.scl3.mozilla.com:9200']
# default to storing logcat output for emulator runs
if options.emulator and not options.logcat_dir:
options.logcat_dir = 'logcat'
if options.emulator and not options.logdir:
options.logdir = 'logcat'
# check for valid resolution string, strip whitespaces
try:
@ -562,11 +558,11 @@ class BaseMarionetteTestRunner(object):
textrunnerclass = MarionetteTextTestRunner
def __init__(self, address=None, emulator=None, emulatorBinary=None,
emulatorImg=None, emulator_res='480x800', homedir=None,
def __init__(self, address=None, emulator=None, emulator_binary=None,
emulator_img=None, emulator_res='480x800', homedir=None,
app=None, app_args=None, bin=None, profile=None, autolog=False,
revision=None, logger=None, testgroup="marionette", noWindow=False,
logcat_dir=None, xml_output=None, repeat=0, gecko_path=None,
revision=None, logger=None, testgroup="marionette", no_window=False,
logdir=None, xml_output=None, repeat=0,
testvars=None, tree=None, type=None, device_serial=None,
symbols_path=None, timeout=None, es_servers=None, shuffle=False,
shuffle_seed=random.randint(0, sys.maxint), sdcard=None,
@ -575,8 +571,8 @@ class BaseMarionetteTestRunner(object):
**kwargs):
self.address = address
self.emulator = emulator
self.emulatorBinary = emulatorBinary
self.emulatorImg = emulatorImg
self.emulator_binary = emulator_binary
self.emulator_img = emulator_img
self.emulator_res = emulator_res
self.homedir = homedir
self.app = app
@ -587,13 +583,12 @@ class BaseMarionetteTestRunner(object):
self.testgroup = testgroup
self.revision = revision
self.logger = logger
self.noWindow = noWindow
self.no_window = no_window
self.httpd = None
self.marionette = None
self.logcat_dir = logcat_dir
self.logdir = logdir
self.xml_output = xml_output
self.repeat = repeat
self.gecko_path = gecko_path
self.testvars = {}
self.test_kwargs = kwargs
self.tree = tree
@ -640,9 +635,9 @@ class BaseMarionetteTestRunner(object):
self.logger.setLevel(logging.INFO)
self.logger.addHandler(logging.StreamHandler())
if self.logcat_dir:
if not os.access(self.logcat_dir, os.F_OK):
os.mkdir(self.logcat_dir)
if self.logdir:
if not os.access(self.logdir, os.F_OK):
os.mkdir(self.logdir)
# for XML output
self.testvars['xml_output'] = self.xml_output
@ -717,8 +712,7 @@ class BaseMarionetteTestRunner(object):
if self.emulator:
kwargs.update({
'homedir': self.homedir,
'logcat_dir': self.logcat_dir,
'gecko_path': self.gecko_path,
'logdir': self.logdir,
})
if self.address:
@ -741,10 +735,10 @@ class BaseMarionetteTestRunner(object):
elif self.emulator:
kwargs.update({
'emulator': self.emulator,
'emulatorBinary': self.emulatorBinary,
'emulatorImg': self.emulatorImg,
'emulator_binary': self.emulator_binary,
'emulator_img': self.emulator_img,
'emulator_res': self.emulator_res,
'noWindow': self.noWindow,
'no_window': self.no_window,
'sdcard': self.sdcard,
})
return kwargs
@ -757,7 +751,7 @@ class BaseMarionetteTestRunner(object):
logfile = None
if self.emulator:
filename = os.path.join(os.path.abspath(self.logcat_dir),
filename = os.path.join(os.path.abspath(self.logdir),
"emulator-%d.log" % self.marionette.emulator.port)
if os.access(filename, os.F_OK):
logfile = filename

View File

@ -9,14 +9,10 @@ import re
def get_dm(marionette=None,**kwargs):
dm_type = os.environ.get('DM_TRANS', 'adb')
if marionette and marionette.emulator:
adb_path = marionette.emulator.b2g.adb_path
return mozdevice.DeviceManagerADB(adbPath=adb_path,
deviceSerial='emulator-%d' % marionette.emulator.port,
**kwargs)
if marionette and hasattr(marionette.runner, 'device'):
return marionette.runner.app_ctx.dm
elif marionette and marionette.device_serial and dm_type == 'adb':
return mozdevice.DeviceManagerADB(deviceSerial=marionette.device_serial,
**kwargs)
return mozdevice.DeviceManagerADB(deviceSerial=marionette.device_serial, **kwargs)
else:
if dm_type == 'adb':
return mozdevice.DeviceManagerADB(**kwargs)

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_test import MarionetteTestCase
from marionette import InvalidElementStateException
from errors import InvalidElementStateException
class TestClear(MarionetteTestCase):
def testWriteableTextInputShouldClear(self):

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_test import MarionetteTestCase
from marionette import MarionetteException
from errors import MarionetteException
class testElementTouch(MarionetteTestCase):
def test_touch(self):

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_test import MarionetteTestCase
from marionette import JavascriptException, MarionetteException
from errors import JavascriptException, MarionetteException
class TestEmulatorContent(MarionetteTestCase):
@ -19,7 +19,7 @@ class TestEmulatorContent(MarionetteTestCase):
def test_emulator_shell(self):
self.marionette.set_script_timeout(10000)
expected = ["Hello World!", ""]
expected = ["Hello World!"]
result = self.marionette.execute_async_script("""
runEmulatorShell(["echo", "Hello World!"], marionetteScriptFinished)
""");

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_test import MarionetteTestCase
from marionette import JavascriptException, MarionetteException, ScriptTimeoutException
from errors import JavascriptException, MarionetteException, ScriptTimeoutException
import time

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_test import MarionetteTestCase, skip_if_b2g
from marionette import JavascriptException, MarionetteException, ScriptTimeoutException
from errors import JavascriptException, MarionetteException, ScriptTimeoutException
class TestExecuteIsolationContent(MarionetteTestCase):
def setUp(self):

View File

@ -5,7 +5,7 @@
import urllib
from by import By
from marionette import JavascriptException, MarionetteException
from errors import JavascriptException, MarionetteException
from marionette_test import MarionetteTestCase
def inline(doc):

View File

@ -5,7 +5,7 @@
from marionette_test import MarionetteTestCase
from marionette import HTMLElement
from by import By
from marionette import NoSuchElementException
from errors import NoSuchElementException
class TestElements(MarionetteTestCase):

View File

@ -5,7 +5,7 @@
from marionette_test import MarionetteTestCase
from marionette import HTMLElement
from by import By
from marionette import NoSuchElementException
from errors import NoSuchElementException
class TestElementsChrome(MarionetteTestCase):

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_test import MarionetteTestCase
from marionette import NoSuchElementException
from errors import NoSuchElementException
class TestImplicitWaits(MarionetteTestCase):
def testShouldImplicitlyWaitForASingleElement(self):

View File

@ -3,8 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette_test import MarionetteTestCase
from marionette import MarionetteException
from marionette import TimeoutException
from errors import MarionetteException, TimeoutException
class TestNavigate(MarionetteTestCase):
def test_navigate(self):

View File

@ -4,9 +4,9 @@
# 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/.
from emulator_screen import EmulatorScreen
from marionette import MarionetteException
from errors import MarionetteException
from marionette_test import MarionetteTestCase
from mozrunner.devices.emulator_screen import EmulatorScreen
default_orientation = "portrait-primary"
unknown_orientation = "Unknown screen orientation: %s"

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