import changes from torbrowser-esr45.9-6.5:

bug21795, bug21514, bug1238694, bug1234246, bug1249522, bug1291543, bug1263334, bug1236639, bug1266963
This commit is contained in:
2018-06-12 11:11:56 +08:00
parent 968484d318
commit e96dfd55a1
29 changed files with 383 additions and 161 deletions
@@ -25,6 +25,7 @@ support-files =
bug792517.html
bug792517.sjs
bug839103.css
clipboard_pastefile.html
discovery.html
domplate_test.js
download_page.html
@@ -283,6 +284,7 @@ skip-if = os == 'win' || e10s # Bug 1159268 - Need a content-process safe versio
[browser_canonizeURL.js]
skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
[browser_clipboard.js]
[browser_clipboard_pastefile.js]
[browser_contentAreaClick.js]
[browser_contextSearchTabPosition.js]
skip-if = os == "mac" || e10s # bug 967013; e10s: bug 1094761 - test hits the network in e10s, causing next test to crash
@@ -0,0 +1,59 @@
// This test is used to check that pasting files removes all non-file data from
// event.clipboardData.
add_task(function*() {
var searchbar = document.getElementById("searchbar");
searchbar.focus();
searchbar.value = "Text";
searchbar.select();
yield new Promise((resolve, reject) => {
searchbar.addEventListener("copy", function copyEvent(event) {
searchbar.removeEventListener("copy", copyEvent, true);
event.clipboardData.setData("text/plain", "Alternate");
// For this test, it doesn't matter that the file isn't actually a file.
event.clipboardData.setData("application/x-moz-file", "Sample");
event.preventDefault();
resolve();
}, true)
EventUtils.synthesizeKey("c", { accelKey: true });
});
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
"https://example.com/browser/browser/base/content/test/general/clipboard_pastefile.html");
let browser = tab.linkedBrowser;
yield ContentTask.spawn(browser, { }, function* (arg) {
content.document.getElementById("input").focus();
});
yield BrowserTestUtils.synthesizeKey("v", { accelKey: true }, browser);
let output = yield ContentTask.spawn(browser, { }, function* (arg) {
return content.document.getElementById("output").textContent;
});
is (output, "Passed", "Paste file");
searchbar.focus();
yield new Promise((resolve, reject) => {
searchbar.addEventListener("paste", function copyEvent(event) {
searchbar.removeEventListener("paste", copyEvent, true);
let dt = event.clipboardData;
is(dt.types.length, 3, "number of types");
ok(dt.types.contains("text/plain"), "text/plain exists in types");
ok(dt.mozTypesAt(0).contains("text/plain"), "text/plain exists in mozTypesAt");
is(dt.getData("text/plain"), "Alternate", "text/plain returned in getData");
is(dt.mozGetDataAt("text/plain", 0), "Alternate", "text/plain returned in mozGetDataAt");
resolve();
}, true);
EventUtils.synthesizeKey("v", { accelKey: true });
});
yield BrowserTestUtils.removeTab(tab);
});
@@ -0,0 +1,37 @@
<html><body>
<script>
function checkPaste(event)
{
let output = document.getElementById("output");
output.textContent = checkPasteHelper(event);
}
function checkPasteHelper(event)
{
let dt = event.clipboardData;
if (dt.types.length != 2)
return "Wrong number of types; got " + dt.types.length;
for (let type of dt.types) {
if (type != "Files" && type != "application/x-moz-file")
return "Invalid type for types; got" + type;
}
for (let type of dt.mozTypesAt(0)) {
if (type != "Files" && type != "application/x-moz-file")
return "Invalid type for mozTypesAt; got" + type;
}
if (dt.getData("text/plain"))
return "text/plain found with getData";
if (dt.mozGetDataAt("text/plain", 0))
return "text/plain found with mozGetDataAt";
return "Passed";
}
</script>
<input id="input" onpaste="checkPaste(event)">
<div id="output"></div>
</body></html>
+36 -24
View File
@@ -359,25 +359,8 @@ DataTransfer::GetFiles(nsIDOMFileList** aFileList)
already_AddRefed<DOMStringList>
DataTransfer::Types()
{
RefPtr<DOMStringList> types = new DOMStringList();
if (mItems.Length()) {
bool addFile = false;
const nsTArray<TransferItem>& item = mItems[0];
for (uint32_t i = 0; i < item.Length(); i++) {
const nsString& format = item[i].mFormat;
types->Add(format);
if (!addFile) {
addFile = format.EqualsASCII(kFileMime) ||
format.EqualsASCII("application/x-moz-file-promise");
}
}
if (addFile) {
types->Add(NS_LITERAL_STRING("Files"));
}
}
return types.forget();
ErrorResult rv;
return MozTypesAt(0, rv);
}
NS_IMETHODIMP
@@ -545,7 +528,7 @@ DataTransfer::GetMozSourceNode(nsIDOMNode** aSourceNode)
}
already_AddRefed<DOMStringList>
DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv)
DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv) const
{
// Only the first item is valid for clipboard events
if (aIndex > 0 &&
@@ -557,10 +540,28 @@ DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv)
RefPtr<DOMStringList> types = new DOMStringList();
if (aIndex < mItems.Length()) {
bool addFile = false;
// note that you can retrieve the types regardless of their principal
nsTArray<TransferItem>& item = mItems[aIndex];
for (uint32_t i = 0; i < item.Length(); i++)
types->Add(item[i].mFormat);
const nsTArray<TransferItem>& item = mItems[aIndex];
for (uint32_t i = 0; i < item.Length(); i++) {
const nsString& format = item[i].mFormat;
types->Add(format);
if (!addFile) {
addFile = format.EqualsASCII(kFileMime);
}
}
if (addFile) {
// If this is a content caller, and a file is in the data transfer, remove
// the non-file types. This prevents alternate text forms of the file
// from being returned.
if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
types->Clear();
types->Add(NS_LITERAL_STRING(kFileMime));
}
types->Add(NS_LITERAL_STRING("Files"));
}
}
return types.forget();
@@ -602,12 +603,23 @@ DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
nsAutoString format;
GetRealFormat(aFormat, format);
nsTArray<TransferItem>& item = mItems[aIndex];
// If this is a content caller, and a file is in the data transfer, only
// return the file type.
if (!format.EqualsLiteral(kFileMime) &&
!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) {
uint32_t count = item.Length();
for (uint32_t i = 0; i < count; i++) {
if (item[i].mFormat.EqualsLiteral(kFileMime)) {
return NS_OK;
}
}
}
// Check if the caller is allowed to access the drag data. Callers with
// chrome privileges can always read the data. During the
// drop event, allow retrieving the data except in the case where the
+2 -1
View File
@@ -165,7 +165,8 @@ public:
}
}
already_AddRefed<DOMStringList> MozTypesAt(uint32_t aIndex,
mozilla::ErrorResult& aRv);
mozilla::ErrorResult& aRv) const;
void MozClearDataAt(const nsAString& aFormat, uint32_t aIndex,
mozilla::ErrorResult& aRv);
void MozSetDataAt(JSContext* aCx, const nsAString& aFormat,
+23 -7
View File
@@ -204,7 +204,7 @@ MP3TrackDemuxer::FastSeek(const TimeUnit& aTime) {
if (!aTime.ToMicroseconds()) {
// Quick seek to the beginning of the stream.
mFrameIndex = 0;
} else if (vbr.IsTOCPresent()) {
} else if (vbr.IsTOCPresent() && Duration().ToMicroseconds() > 0) {
// Use TOC for more precise seeking.
const float durationFrac = static_cast<float>(aTime.ToMicroseconds()) /
Duration().ToMicroseconds();
@@ -347,7 +347,7 @@ MP3TrackDemuxer::Duration() const {
int64_t numFrames = 0;
const auto numAudioFrames = mParser.VBRInfo().NumAudioFrames();
if (numAudioFrames) {
if (mParser.VBRInfo().IsValid() && numAudioFrames.valueOr(0) + 1 > 1) {
// VBR headers don't include the VBR header frame.
numFrames = numAudioFrames.value() + 1;
} else {
@@ -356,7 +356,9 @@ MP3TrackDemuxer::Duration() const {
// Unknown length, we can't estimate duration.
return TimeUnit::FromMicroseconds(-1);
}
numFrames = (streamLen - mFirstFrameOffset) / AverageFrameLength();
if (AverageFrameLength() > 0) {
numFrames = (streamLen - mFirstFrameOffset) / AverageFrameLength();
}
}
return Duration(numFrames);
}
@@ -511,7 +513,6 @@ MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange) {
if (mNumParsedFrames == 1) {
// First frame parsed, let's read VBR info if available.
// TODO: read info that helps with seeking (bug 1163667).
ByteReader reader(frame->Data(), frame->Size());
mParser.ParseVBRHeader(&reader);
reader.DiscardRemaining();
@@ -532,7 +533,7 @@ MP3TrackDemuxer::OffsetFromFrameIndex(int64_t aFrameIndex) const {
int64_t offset = 0;
const auto& vbr = mParser.VBRInfo();
if (vbr.NumBytes() && vbr.NumAudioFrames()) {
if (vbr.IsComplete()) {
offset = mFirstFrameOffset + aFrameIndex * vbr.NumBytes().value() /
vbr.NumAudioFrames().value();
} else if (AverageFrameLength() > 0) {
@@ -548,7 +549,7 @@ MP3TrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const {
int64_t frameIndex = 0;
const auto& vbr = mParser.VBRInfo();
if (vbr.NumBytes() && vbr.NumAudioFrames()) {
if (vbr.IsComplete()) {
frameIndex = static_cast<float>(aOffset - mFirstFrameOffset) /
vbr.NumBytes().value() * vbr.NumAudioFrames().value();
frameIndex = std::min<int64_t>(vbr.NumAudioFrames().value(), frameIndex);
@@ -624,7 +625,7 @@ MP3TrackDemuxer::AverageFrameLength() const {
return static_cast<double>(mTotalFrameLen) / mNumParsedFrames;
}
const auto& vbr = mParser.VBRInfo();
if (vbr.NumBytes() && vbr.NumAudioFrames()) {
if (vbr.IsComplete() && vbr.NumAudioFrames().value() + 1) {
return static_cast<double>(vbr.NumBytes().value()) /
(vbr.NumAudioFrames().value() + 1);
}
@@ -960,6 +961,21 @@ FrameParser::VBRHeader::IsTOCPresent() const {
return mTOC.size() == vbr_header::TOC_SIZE;
}
bool
FrameParser::VBRHeader::IsValid() const {
return mType != NONE;
}
bool
FrameParser::VBRHeader::IsComplete() const {
return IsValid() &&
mNumAudioFrames.valueOr(0) > 0 &&
mNumBytes.valueOr(0) > 0 &&
// We don't care about the scale for any computations here.
// mScale < 101 &&
true;
}
int64_t
FrameParser::VBRHeader::Offset(float aDurationFac) const {
if (!IsTOCPresent()) {
+6
View File
@@ -232,6 +232,12 @@ public:
// Returns true iff Xing/Info TOC (table of contents) is present.
bool IsTOCPresent() const;
// Returns whether the header is valid (type XING or VBRI).
bool IsValid() const;
// Returns whether the header is valid and contains reasonable non-zero field values.
bool IsComplete() const;
// Returns the byte offset for the given duration percentage as a factor
// (0: begin, 1.0: end).
int64_t Offset(float aDurationFac) const;
+17 -2
View File
@@ -18,6 +18,7 @@
#include "asmjs/AsmJSModule.h"
#include "mozilla/Atomics.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/Compression.h"
#include "mozilla/EnumeratedRange.h"
@@ -51,6 +52,7 @@ using namespace js;
using namespace js::jit;
using namespace js::wasm;
using namespace js::frontend;
using mozilla::Atomic;
using mozilla::BinarySearch;
using mozilla::Compression::LZ4;
using mozilla::MakeEnumeratedRange;
@@ -61,6 +63,12 @@ using mozilla::PodZero;
using mozilla::Swap;
using JS::GenericNaN;
// Limit the number of concurrent wasm code allocations per process. Note that
// on Linux, the real maximum is ~32k, as each module requires 2 maps (RW/RX),
// and the kernel's default max_map_count is ~65k.
static Atomic<uint32_t> wasmCodeAllocations(0);
static const uint32_t MaxWasmCodeAllocations = 16384;
static uint8_t*
AllocateExecutableMemory(ExclusiveContext* cx, size_t bytes)
{
@@ -68,9 +76,14 @@ AllocateExecutableMemory(ExclusiveContext* cx, size_t bytes)
// a multiple of ExecutableCodePageSize.
bytes = JS_ROUNDUP(bytes, ExecutableCodePageSize);
void* p = AllocateExecutableMemory(bytes, ProtectionSetting::Writable);
if (!p)
void* p = nullptr;
if (wasmCodeAllocations++ < MaxWasmCodeAllocations)
p = AllocateExecutableMemory(bytes, ProtectionSetting::Writable);
if (!p) {
wasmCodeAllocations--;
ReportOutOfMemory(cx);
}
return (uint8_t*)p;
}
@@ -122,6 +135,8 @@ AsmJSModule::~AsmJSModule()
}
uint32_t size = JS_ROUNDUP(pod.totalBytes_, ExecutableCodePageSize);
MOZ_ASSERT(wasmCodeAllocations > 0);
wasmCodeAllocations--;
DeallocateExecutableMemory(code_, size);
}
@@ -465,8 +465,6 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
writePerfSpewerJitCodeProfile(code, "RegExp");
#endif
AutoWritableJitCode awjc(code);
for (size_t i = 0; i < labelPatches.length(); i++) {
LabelPatch& v = labelPatches[i];
MOZ_ASSERT(!v.label);
+1 -3
View File
@@ -249,14 +249,12 @@ BaselineCompiler::compile()
// All barriers are emitted off-by-default, toggle them on if needed.
if (cx->zone()->needsIncrementalBarrier())
baselineScript->toggleBarriers(true);
baselineScript->toggleBarriers(true, DontReprotect);
// If profiler instrumentation is enabled, toggle instrumentation on.
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
baselineScript->toggleProfilerInstrumentation(true);
AutoWritableJitCode awjc(code);
// Patch IC loads using IC entries.
for (size_t i = 0; i < icLoadLabels_.length(); i++) {
CodeOffset label = icLoadLabels_[i].label;
+5 -2
View File
@@ -1028,8 +1028,6 @@ BaselineScript::toggleProfilerInstrumentation(bool enable)
JitSpew(JitSpew_BaselineIC, " toggling profiling %s for BaselineScript %p",
enable ? "on" : "off", this);
AutoWritableJitCode awjc(method());
// Toggle the jump
CodeLocationLabel enterToggleLocation(method_, CodeOffset(profilerEnterToggleOffset_));
CodeLocationLabel exitToggleLocation(method_, CodeOffset(profilerExitToggleOffset_));
@@ -1141,11 +1139,16 @@ jit::AddSizeOfBaselineData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf,
void
jit::ToggleBaselineProfiling(JSRuntime* runtime, bool enable)
{
JitRuntime* jrt = runtime->jitRuntime();
if (!jrt)
return;
for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
for (gc::ZoneCellIter i(zone, gc::AllocKind::SCRIPT); !i.done(); i.next()) {
JSScript* script = i.get<JSScript>();
if (!script->hasBaselineScript())
continue;
AutoWritableJitCode awjc(script->baselineScript()->method());
script->baselineScript()->toggleProfilerInstrumentation(enable);
}
}
+2 -2
View File
@@ -356,8 +356,8 @@ struct BaselineScript
templateScope_ = templateScope;
}
void toggleBarriers(bool enabled) {
method()->togglePreBarriers(enabled);
void toggleBarriers(bool enabled, ReprotectCode reprotect = Reprotect) {
method()->togglePreBarriers(enabled, reprotect);
}
bool containsCodeAddress(uint8_t* addr) const {
+49 -52
View File
@@ -1446,7 +1446,7 @@ JitCompartment::generateRegExpExecStub(JSContext* cx)
#endif
if (cx->zone()->needsIncrementalBarrier())
code->togglePreBarriers(true);
code->togglePreBarriers(true, DontReprotect);
return code;
}
@@ -1579,7 +1579,7 @@ JitCompartment::generateRegExpTestStub(JSContext* cx)
#endif
if (cx->zone()->needsIncrementalBarrier())
code->togglePreBarriers(true);
code->togglePreBarriers(true, DontReprotect);
return code;
}
@@ -8263,61 +8263,58 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
// Adopt fallback shared stubs from the compiler into the ion script.
ionScript->adoptFallbackStubs(&stubSpace_);
{
AutoWritableJitCode awjc(code);
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
ImmPtr(ionScript),
ImmPtr((void*)-1));
for (size_t i = 0; i < ionScriptLabels_.length(); i++) {
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, ionScriptLabels_[i]),
ImmPtr(ionScript),
ImmPtr((void*)-1));
for (size_t i = 0; i < ionScriptLabels_.length(); i++) {
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, ionScriptLabels_[i]),
ImmPtr(ionScript),
ImmPtr((void*)-1));
}
}
#ifdef JS_TRACE_LOGGING
TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
for (uint32_t i = 0; i < patchableTraceLoggers_.length(); i++) {
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTraceLoggers_[i]),
ImmPtr(logger),
ImmPtr(nullptr));
}
if (patchableTLScripts_.length() > 0) {
MOZ_ASSERT(TraceLogTextIdEnabled(TraceLogger_Scripts));
TraceLoggerEvent event(logger, TraceLogger_Scripts, script);
ionScript->setTraceLoggerEvent(event);
uint32_t textId = event.payload()->textId();
for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
ImmPtr((void*) uintptr_t(textId)),
ImmPtr((void*)0));
}
}
#endif
// Patch shared stub IC loads using IC entries
for (size_t i = 0; i < sharedStubs_.length(); i++) {
CodeOffset label = sharedStubs_[i].label;
IonICEntry& entry = ionScript->sharedStubList()[i];
entry = sharedStubs_[i].entry;
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, label),
ImmPtr(&entry),
ImmPtr((void*)-1));
MOZ_ASSERT(entry.hasStub());
MOZ_ASSERT(entry.firstStub()->isFallback());
entry.firstStub()->toFallbackStub()->fixupICEntry(&entry);
}
// for generating inline caches during the execution.
if (runtimeData_.length())
ionScript->copyRuntimeData(&runtimeData_[0]);
if (cacheList_.length())
ionScript->copyCacheEntries(&cacheList_[0], masm);
TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
for (uint32_t i = 0; i < patchableTraceLoggers_.length(); i++) {
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTraceLoggers_[i]),
ImmPtr(logger),
ImmPtr(nullptr));
}
if (patchableTLScripts_.length() > 0) {
MOZ_ASSERT(TraceLogTextIdEnabled(TraceLogger_Scripts));
TraceLoggerEvent event(logger, TraceLogger_Scripts, script);
ionScript->setTraceLoggerEvent(event);
uint32_t textId = event.payload()->textId();
for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
ImmPtr((void*) uintptr_t(textId)),
ImmPtr((void*)0));
}
}
#endif
// Patch shared stub IC loads using IC entries
for (size_t i = 0; i < sharedStubs_.length(); i++) {
CodeOffset label = sharedStubs_[i].label;
IonICEntry& entry = ionScript->sharedStubList()[i];
entry = sharedStubs_[i].entry;
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, label),
ImmPtr(&entry),
ImmPtr((void*)-1));
MOZ_ASSERT(entry.hasStub());
MOZ_ASSERT(entry.firstStub()->isFallback());
entry.firstStub()->toFallbackStub()->fixupICEntry(&entry);
}
// for generating inline caches during the execution.
if (runtimeData_.length())
ionScript->copyRuntimeData(&runtimeData_[0]);
if (cacheList_.length())
ionScript->copyCacheEntries(&cacheList_[0], masm);
JitSpew(JitSpew_Codegen, "Created IonScript %p (raw %p)",
(void*) ionScript, (void*) code->raw());
@@ -8367,7 +8364,7 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
// since a GC can occur during code generation. All barriers are emitted
// off-by-default, and are toggled on here if necessary.
if (cx->zone()->needsIncrementalBarrier())
ionScript->toggleBarriers(true);
ionScript->toggleBarriers(true, DontReprotect);
// Attach any generated script counts to the script.
if (IonScriptCounts* counts = extractScriptCounts())
+2
View File
@@ -372,10 +372,12 @@ class ExecutableAllocator
static void makeWritable(void* start, size_t size)
{
ReprotectRegion(start, size, ProtectionSetting::Writable);
}
static void makeExecutable(void* start, size_t size)
{
ReprotectRegion(start, size, ProtectionSetting::Executable);
}
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+12 -9
View File
@@ -744,14 +744,14 @@ JitCompartment::toggleBarriers(bool enabled)
{
// Toggle barriers in compartment wide stubs that have patchable pre barriers.
if (regExpExecStub_)
regExpExecStub_->togglePreBarriers(enabled);
regExpExecStub_->togglePreBarriers(enabled, Reprotect);
if (regExpTestStub_)
regExpTestStub_->togglePreBarriers(enabled);
regExpTestStub_->togglePreBarriers(enabled, Reprotect);
// Toggle barriers in baseline IC stubs.
for (ICStubCodeMap::Enum e(*stubCodes_); !e.empty(); e.popFront()) {
JitCode* code = *e.front().value().unsafeGet();
code->togglePreBarriers(enabled);
code->togglePreBarriers(enabled, Reprotect);
}
}
@@ -879,20 +879,23 @@ JitCode::finalize(FreeOp* fop)
}
void
JitCode::togglePreBarriers(bool enabled)
JitCode::togglePreBarriers(bool enabled, ReprotectCode reprotect)
{
AutoWritableJitCode awjc(this);
uint8_t* start = code_ + preBarrierTableOffset();
CompactBufferReader reader(start, start + preBarrierTableBytes_);
while (reader.more()) {
if (!reader.more())
return;
MaybeAutoWritableJitCode awjc(this, reprotect);
do {
size_t offset = reader.readUnsigned();
CodeLocationLabel loc(this, CodeOffset(offset));
if (enabled)
Assembler::ToggleToCmp(loc);
else
Assembler::ToggleToJmp(loc);
}
} while (reader.more());
}
IonScript::IonScript()
@@ -1270,9 +1273,9 @@ IonScript::Destroy(FreeOp* fop, IonScript* script)
}
void
IonScript::toggleBarriers(bool enabled)
IonScript::toggleBarriers(bool enabled, ReprotectCode reprotect)
{
method()->togglePreBarriers(enabled);
method()->togglePreBarriers(enabled, reprotect);
}
void
+6 -1
View File
@@ -6374,7 +6374,12 @@ IonBuilder::jsop_funapply(uint32_t argc)
if (argument->type() != MIRType_MagicOptimizedArguments) {
// Optimize fun.apply(self, array) if the length is sane and there are no holes.
TemporaryTypeSet* objTypes = argument->resultTypeSet();
if (native && native->isNative() && native->native() == fun_apply &&
#ifdef XP_WIN
bool opt = false;
#else
bool opt = true;
#endif
if (opt && native && native->isNative() && native->native() == fun_apply &&
objTypes &&
objTypes->getKnownClass(constraints()) == &ArrayObject::class_ &&
!objTypes->hasObjectFlags(constraints(), OBJECT_FLAG_LENGTH_OVERFLOW) &&
+27 -27
View File
@@ -99,20 +99,6 @@ IonCache::CacheName(IonCache::Kind kind)
return names[kind];
}
IonCache::LinkStatus
IonCache::linkCode(JSContext* cx, MacroAssembler& masm, IonScript* ion, JitCode** code)
{
Linker linker(masm);
*code = linker.newCode<CanGC>(cx, ION_CODE);
if (!*code)
return LINK_ERROR;
if (ion->invalidated())
return CACHE_FLUSHED;
return LINK_GOOD;
}
const size_t IonCache::MAX_STUBS = 16;
// Helper class which encapsulates logic to attach a stub to an IC by hooking
@@ -239,27 +225,20 @@ class IonCache::StubAttacher
void patchRejoinJump(MacroAssembler& masm, JitCode* code) {
rejoinOffset_.fixup(&masm);
CodeLocationJump rejoinJump(code, rejoinOffset_);
AutoWritableJitCode awjc(code);
PatchJump(rejoinJump, rejoinLabel_);
}
void patchStubCodePointer(JitCode* code) {
if (hasStubCodePatchOffset_) {
AutoWritableJitCode awjc(code);
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, stubCodePatchOffset_),
ImmPtr(code), STUB_ADDR);
}
}
void patchNextStubJump(MacroAssembler& masm, JitCode* code) {
// Patch the previous nextStubJump of the last stub, or the jump from the
// codeGen, to jump into the newly allocated code.
PatchJump(cache_.lastJump_, CodeLocationLabel(code), Reprotect);
// If this path is not taken, we are producing an entry which can no
// longer go back into the update function.
if (hasNextStubOffset_) {
AutoWritableJitCode awjc(code);
nextStubOffset_.fixup(&masm);
CodeLocationJump nextStubJump(code, nextStubOffset_);
PatchJump(nextStubJump, cache_.fallbackLabel_);
@@ -285,21 +264,41 @@ IonCache::emitInitialJump(MacroAssembler& masm, RepatchLabel& entry)
}
void
IonCache::attachStub(MacroAssembler& masm, StubAttacher& attacher, Handle<JitCode*> code)
IonCache::attachStub(MacroAssembler& masm, StubAttacher& attacher, CodeLocationJump lastJump,
Handle<JitCode*> code)
{
MOZ_ASSERT(canAttachStub());
incrementStubCount();
// Patch the previous nextStubJump of the last stub, or the jump from the
// codeGen, to jump into the newly allocated code.
PatchJump(lastJump, CodeLocationLabel(code), Reprotect);
}
IonCache::LinkStatus
IonCache::linkCode(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher, IonScript* ion,
JitCode** code)
{
Linker linker(masm);
*code = linker.newCode<CanGC>(cx, ION_CODE);
if (!*code)
return LINK_ERROR;
if (ion->invalidated())
return CACHE_FLUSHED;
// Update the success path to continue after the IC initial jump.
attacher.patchRejoinJump(masm, code);
attacher.patchRejoinJump(masm, *code);
// Replace the STUB_ADDR constant by the address of the generated stub, such
// as it can be kept alive even if the cache is flushed (see
// MarkJitExitFrame).
attacher.patchStubCodePointer(code);
attacher.patchStubCodePointer(*code);
// Update the failure path.
attacher.patchNextStubJump(masm, code);
attacher.patchNextStubJump(masm, *code);
return LINK_GOOD;
}
bool
@@ -307,12 +306,13 @@ IonCache::linkAndAttachStub(JSContext* cx, MacroAssembler& masm, StubAttacher& a
IonScript* ion, const char* attachKind,
JS::TrackedOutcome trackedOutcome)
{
CodeLocationJump lastJumpBefore = lastJump_;
Rooted<JitCode*> code(cx);
{
// Need to exit the AutoFlushICache context to flush the cache
// before attaching the stub below.
AutoFlushICache afc("IonCache");
LinkStatus status = linkCode(cx, masm, ion, code.address());
LinkStatus status = linkCode(cx, masm, attacher, ion, code.address());
if (status != LINK_GOOD)
return status != LINK_ERROR;
}
@@ -330,7 +330,7 @@ IonCache::linkAndAttachStub(JSContext* cx, MacroAssembler& masm, StubAttacher& a
writePerfSpewerJitCodeProfile(code, "IonCache");
#endif
attachStub(masm, attacher, code);
attachStub(masm, attacher, lastJumpBefore, code);
// Add entry to native => bytecode mapping for this stub if needed.
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime())) {
+5 -2
View File
@@ -293,10 +293,13 @@ class IonCache
// monitoring/allocation caused an invalidation of the running ion script,
// this function returns CACHE_FLUSHED. In case of allocation issue this
// function returns LINK_ERROR.
LinkStatus linkCode(JSContext* cx, MacroAssembler& masm, IonScript* ion, JitCode** code);
LinkStatus linkCode(JSContext* cx, MacroAssembler& masm, StubAttacher& attacher, IonScript* ion,
JitCode** code);
// Fixup variables and update jumps in the list of stubs. Increment the
// number of attached stubs accordingly.
void attachStub(MacroAssembler& masm, StubAttacher& attacher, Handle<JitCode*> code);
void attachStub(MacroAssembler& masm, StubAttacher& attacher, CodeLocationJump lastJump,
Handle<JitCode*> code);
// Combine both linkStub and attachStub into one function. In addition, it
// produces a spew augmented with the attachKind string.
+2 -2
View File
@@ -123,7 +123,7 @@ class JitCode : public gc::TenuredCell
hasBytecodeMap_ = true;
}
void togglePreBarriers(bool enabled);
void togglePreBarriers(bool enabled, ReprotectCode reprotect);
// If this JitCode object has been, effectively, corrupted due to
// invalidation patching, then we have to remember this so we don't try and
@@ -512,7 +512,7 @@ struct IonScript
MOZ_ASSERT(locIndex < runtimeSize_);
return (CacheLocation*) &runtimeData()[locIndex];
}
void toggleBarriers(bool enabled);
void toggleBarriers(bool enabled, ReprotectCode reprotect = Reprotect);
void purgeCaches();
void unlinkFromRuntime(FreeOp* fop);
void copySnapshots(const SnapshotWriter* writer);
+2
View File
@@ -776,6 +776,8 @@ enum class BarrierKind : uint32_t {
TypeSet
};
enum ReprotectCode { Reprotect = true, DontReprotect = false };
} // namespace jit
} // namespace js
-2
View File
@@ -518,8 +518,6 @@ class MOZ_STACK_CLASS AutoWritableJitCode
}
};
enum ReprotectCode { Reprotect = true, DontReprotect = false };
class MOZ_STACK_CLASS MaybeAutoWritableJitCode
{
mozilla::Maybe<AutoWritableJitCode> awjc_;
+2 -1
View File
@@ -22,6 +22,7 @@ namespace jit {
class Linker
{
MacroAssembler& masm;
mozilla::Maybe<AutoWritableJitCode> awjc;
JitCode* fail(JSContext* cx) {
ReportOutOfMemory(cx);
@@ -68,7 +69,7 @@ class Linker
return nullptr;
if (masm.oom())
return fail(cx);
AutoWritableJitCode awjc(result, bytesNeeded);
awjc.emplace(result, bytesNeeded);
code->copyFrom(masm);
masm.link(code);
if (masm.embedsNurseryPointers())
+1 -11
View File
@@ -2304,17 +2304,7 @@ LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment* ins)
void
LIRGenerator::visitInterruptCheck(MInterruptCheck* ins)
{
// Implicit interrupt checks require asm.js signal handlers to be installed.
// They also require writable JIT code: reprotecting in patchIonBackedges
// would be expensive and using AutoWritableJitCode in the signal handler
// is complicated because there could be another AutoWritableJitCode on the
// stack.
LInstructionHelper<0, 0, 0>* lir;
if (GetJitContext()->runtime->canUseSignalHandlers()) {
lir = new(alloc()) LInterruptCheckImplicit();
} else {
lir = new(alloc()) LInterruptCheck();
}
LInstructionHelper<0, 0, 0>* lir = new(alloc()) LInterruptCheck();
add(lir, ins);
assignSafepoint(lir, ins);
}
+46 -2
View File
@@ -219,7 +219,12 @@ DeallocateProcessExecutableMemory(void* addr, size_t bytes)
static DWORD
ProtectionSettingToFlags(ProtectionSetting protection)
{
return PAGE_EXECUTE_READWRITE;
switch (protection) {
case ProtectionSetting::Protected: return PAGE_NOACCESS;
case ProtectionSetting::Writable: return PAGE_READWRITE;
case ProtectionSetting::Executable: return PAGE_EXECUTE_READ;
}
MOZ_CRASH();
}
static void
@@ -283,7 +288,12 @@ DeallocateProcessExecutableMemory(void* addr, size_t bytes)
static unsigned
ProtectionSettingToFlags(ProtectionSetting protection)
{
return PROT_READ | PROT_WRITE | PROT_EXEC;
switch (protection) {
case ProtectionSetting::Protected: return PROT_NONE;
case ProtectionSetting::Writable: return PROT_READ | PROT_WRITE;
case ProtectionSetting::Executable: return PROT_READ | PROT_EXEC;
}
MOZ_CRASH();
}
static void
@@ -605,3 +615,37 @@ js::jit::CanLikelyAllocateMoreExecutableMemory()
return execMemory.bytesAllocated() + BufferSize <= MaxCodeBytesPerProcess;
}
bool
js::jit::ReprotectRegion(void* start, size_t size, ProtectionSetting protection)
{
// Calculate the start of the page containing this region,
// and account for this extra memory within size.
size_t pageSize = gc::SystemPageSize();
intptr_t startPtr = reinterpret_cast<intptr_t>(start);
intptr_t pageStartPtr = startPtr & ~(pageSize - 1);
void* pageStart = reinterpret_cast<void*>(pageStartPtr);
size += (startPtr - pageStartPtr);
// Round size up
size += (pageSize - 1);
size &= ~(pageSize - 1);
MOZ_ASSERT((uintptr_t(pageStart) % pageSize) == 0);
execMemory.assertValidAddress(pageStart, size);
#ifdef XP_WIN
DWORD oldProtect;
DWORD flags = ProtectionSettingToFlags(protection);
if (!VirtualProtect(pageStart, size, flags, &oldProtect))
return false;
#else
unsigned flags = ProtectionSettingToFlags(protection);
if (mprotect(pageStart, size, flags))
return false;
#endif
execMemory.assertValidAddress(pageStart, size);
return true;
}
+2
View File
@@ -23,6 +23,8 @@ enum class ProtectionSetting {
Executable,
};
extern MOZ_MUST_USE bool ReprotectRegion(void* start, size_t size, ProtectionSetting protection);
// Functions called at process start-up/shutdown to initialize/release the
// executable memory region.
extern MOZ_MUST_USE bool InitProcessExecutableMemory();
+1 -1
View File
@@ -748,7 +748,7 @@ ICStubCompiler::getStubCode()
// All barriers are emitted off-by-default, enable them if needed.
if (cx->zone()->needsIncrementalBarrier())
newStubCode->togglePreBarriers(true);
newStubCode->togglePreBarriers(true, DontReprotect);
// Cache newly compiled stubcode.
if (!comp->putStubCode(cx, stubKey, newStubCode))
+9 -7
View File
@@ -2517,6 +2517,12 @@ nsXULPopupManager::KeyDown(nsIDOMKeyEvent* aKeyEvent)
if (!mActiveMenuBar && (!item || item->PopupType() != ePopupTypeMenu))
return NS_OK;
// Since a menu was open, stop propagation of the event to keep other event
// listeners from becoming confused.
if (!item || item->IgnoreKeys() != eIgnoreKeys_Handled) {
aKeyEvent->StopPropagation();
}
int32_t menuAccessKey = -1;
// If the key just pressed is the access key (usually Alt),
@@ -2547,19 +2553,15 @@ nsXULPopupManager::KeyDown(nsIDOMKeyEvent* aKeyEvent)
Rollup(0, false, nullptr, nullptr);
else if (mActiveMenuBar)
mActiveMenuBar->MenuClosed();
// Clear the item to avoid bugs as it may have been deleted during rollup.
item = nullptr;
}
aKeyEvent->StopPropagation();
aKeyEvent->PreventDefault();
}
}
// Since a menu was open, stop propagation of the event to keep other event
// listeners from becoming confused.
if (!item || item->IgnoreKeys() != eIgnoreKeys_Handled) {
aKeyEvent->StopPropagation();
}
aKeyEvent->StopCrossProcessForwarding();
return NS_OK;
}
@@ -65,7 +65,9 @@
var dragfile = [[
{ type : "application/x-moz-file",
data : testFile,
eqTest : function(actualData, expectedData) {return expectedData.equals(actualData);} }
eqTest : function(actualData, expectedData) {return expectedData.equals(actualData);} },
{ type : "Files",
data : null }
]];
function doOnDrop(aEvent) {
@@ -706,6 +706,30 @@ var popupTests = [
}
},
{
testname: "Open menu and press alt key by itself - open menu",
events: [ "DOMMenuBarActive menubar",
"popupshowing filepopup", "DOMMenuItemActive filemenu",
"DOMMenuItemActive item1", "popupshown filepopup" ],
test: function() { synthesizeKey("F", { altKey: true }); },
result: function (testname) {
checkOpen("filemenu", testname);
}
},
{
testname: "Open menu and press alt key by itself - close menu",
events: [ "popuphiding filepopup", "popuphidden filepopup",
"DOMMenuItemInactive item1", "DOMMenuInactive filepopup",
"DOMMenuBarInactive menubar", "DOMMenuItemInactive filemenu",
"DOMMenuItemInactive filemenu" ],
test: function() {
synthesizeKey("VK_ALT", { });
},
result: function (testname) {
checkClosed("filemenu", testname);
}
},
// Fllowing 4 tests are a test of bug 616797, don't insert any new tests
// between them.
{