зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-central to autoland. r=merge a=merge
This commit is contained in:
Коммит
5e55af8f82
|
@ -1,8 +1,8 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
support-files = script_file.js
|
||||
|
||||
[test_ipcBlob_fileReaderSync.html]
|
||||
support-files = script_file.js
|
||||
[test_ipcBlob_workers.html]
|
||||
[test_ipcBlob_createImageBitmap.html]
|
||||
support-files = green.jpg
|
||||
[test_ipcBlob_emptyMultiplex.html]
|
||||
|
|
|
@ -7,7 +7,7 @@ addMessageListener("file.open", function (e) {
|
|||
.QueryInterface(Ci.nsIProperties)
|
||||
.get("ProfD", Ci.nsIFile);
|
||||
testFile.append("ipc_fileReader_testing");
|
||||
testFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
|
||||
testFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
|
||||
|
||||
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
|
@ -22,3 +22,21 @@ addMessageListener("file.open", function (e) {
|
|||
sendAsyncMessage("file.opened", { file });
|
||||
});
|
||||
});
|
||||
|
||||
addMessageListener("emptyfile.open", function (e) {
|
||||
var testFile = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIDirectoryService)
|
||||
.QueryInterface(Ci.nsIProperties)
|
||||
.get("ProfD", Ci.nsIFile);
|
||||
testFile.append("ipc_fileReader_testing");
|
||||
testFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
|
||||
|
||||
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
|
||||
0666, 0);
|
||||
|
||||
File.createFromNsIFile(testFile).then(function(file) {
|
||||
sendAsyncMessage("emptyfile.opened", { file });
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test an empty IPCBlob together with other parts</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
|
||||
function checkContent(msg, content) {
|
||||
return new Promise(resolve => {
|
||||
let fr = new FileReader();
|
||||
fr.readAsText(new Blob(content));
|
||||
fr.onloadend = () => {
|
||||
is(fr.result, "Hello world!", "The content matches: " + msg);
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let url = SimpleTest.getTestFileURL("script_file.js");
|
||||
|
||||
let script = SpecialPowers.loadChromeScript(url);
|
||||
script.addMessageListener("emptyfile.opened", message => {
|
||||
checkContent("middle", ["Hello ", message.file, "world!"]).
|
||||
then(() => checkContent("begin", [message.file, "Hello world!"])).
|
||||
then(() => checkContent("end", ["Hello world!", message.file])).
|
||||
then(() => checkContent("random", [message.file, message.file, "Hello world!", message.file])).
|
||||
then(SimpleTest.finish);
|
||||
});
|
||||
|
||||
script.sendAsyncMessage("emptyfile.open");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -75,6 +75,8 @@
|
|||
is(v2.videoHeight, v1.videoHeight / 2, "sink is half the height of source");
|
||||
stream.getTracks().forEach(track => track.stop());
|
||||
v1.srcObject = v2.srcObject = null;
|
||||
pc1.close()
|
||||
pc2.close()
|
||||
}
|
||||
|
||||
pushPrefs(['media.peerconnection.video.lock_scaling', true]).then(() => {
|
||||
|
|
|
@ -35,12 +35,13 @@ function handleRequest(request, response)
|
|||
switch (query[0]) {
|
||||
case "blocked":
|
||||
var alreadyUnblocked = getGlobalState(query[1]);
|
||||
|
||||
response.processAsync();
|
||||
if (alreadyUnblocked) {
|
||||
// the unblock request came before the blocked request, just go on and finish synchronously
|
||||
finishBlockedRequest(request, response, query);
|
||||
} else {
|
||||
setGlobalState(response, query[1]);
|
||||
response.processAsync();
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -353,7 +353,7 @@ AsyncImagePipelineManager::ApplyAsyncImages()
|
|||
builder.Finalize(builderContentSize, dl);
|
||||
mApi->SetDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(pipeline->mScBounds.Width(), pipeline->mScBounds.Height()),
|
||||
pipelineId, builderContentSize,
|
||||
dl.dl_desc, dl.dl.inner.data, dl.dl.inner.length,
|
||||
dl.dl_desc, dl.dl,
|
||||
resourceUpdates);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,6 +114,7 @@ gecko_profiler_unregister_thread()
|
|||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
@ -598,6 +599,9 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
|
|||
return IPC_FAIL(this, "Failed to deserialize resource updates");
|
||||
}
|
||||
|
||||
|
||||
wr::Vec_u8 dlData(Move(dl));
|
||||
|
||||
// If id namespaces do not match, it means the command is obsolete, probably
|
||||
// because the tab just moved to a new window.
|
||||
// In that case do not send the commands to webrender.
|
||||
|
@ -609,7 +613,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
|
|||
gfx::Color clearColor(0.f, 0.f, 0.f, 0.f);
|
||||
mApi->SetDisplayList(clearColor, wr::NewEpoch(wrEpoch), LayerSize(aSize.width, aSize.height),
|
||||
mPipelineId, aContentSize,
|
||||
dlDesc, dl.mData, dl.mLen,
|
||||
dlDesc, dlData,
|
||||
resources);
|
||||
|
||||
ScheduleGenerateFrame();
|
||||
|
|
|
@ -265,8 +265,7 @@ WebRenderAPI::SetDisplayList(gfx::Color aBgColor,
|
|||
wr::WrPipelineId pipeline_id,
|
||||
const LayoutSize& content_size,
|
||||
wr::BuiltDisplayListDescriptor dl_descriptor,
|
||||
uint8_t *dl_data,
|
||||
size_t dl_size,
|
||||
wr::Vec_u8& dl_data,
|
||||
ResourceUpdateQueue& aResources)
|
||||
{
|
||||
wr_api_set_display_list(mDocHandle,
|
||||
|
@ -276,8 +275,7 @@ WebRenderAPI::SetDisplayList(gfx::Color aBgColor,
|
|||
pipeline_id,
|
||||
content_size,
|
||||
dl_descriptor,
|
||||
dl_data,
|
||||
dl_size,
|
||||
&dl_data.inner,
|
||||
aResources.Raw());
|
||||
}
|
||||
|
||||
|
|
|
@ -161,8 +161,7 @@ public:
|
|||
wr::WrPipelineId pipeline_id,
|
||||
const wr::LayoutSize& content_size,
|
||||
wr::BuiltDisplayListDescriptor dl_descriptor,
|
||||
uint8_t *dl_data,
|
||||
size_t dl_size,
|
||||
wr::Vec_u8& dl_data,
|
||||
ResourceUpdateQueue& aResources);
|
||||
|
||||
void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId pipeline_id);
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "WebRenderTypes.h"
|
||||
|
||||
#include "mozilla/ipc/ByteBuf.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace wr {
|
||||
|
||||
Vec_u8::Vec_u8(mozilla::ipc::ByteBuf&& aSrc) {
|
||||
inner.data = aSrc.mData;
|
||||
inner.length = aSrc.mLen;
|
||||
inner.capacity = aSrc.mCapacity;
|
||||
aSrc.mData = nullptr;
|
||||
aSrc.mLen = 0;
|
||||
aSrc.mCapacity = 0;
|
||||
}
|
||||
|
||||
} // namespace wr
|
||||
} // namespace mozilla
|
|
@ -21,6 +21,11 @@
|
|||
#include "nsStyleConsts.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace ipc {
|
||||
class ByteBuf;
|
||||
} // namespace ipc
|
||||
|
||||
namespace wr {
|
||||
|
||||
typedef wr::WrWindowId WindowId;
|
||||
|
@ -576,6 +581,8 @@ struct Vec_u8 {
|
|||
src.SetEmpty();
|
||||
}
|
||||
|
||||
explicit Vec_u8(mozilla::ipc::ByteBuf&& aSrc);
|
||||
|
||||
Vec_u8&
|
||||
operator=(Vec_u8&& src) {
|
||||
inner = src.inner;
|
||||
|
|
|
@ -29,6 +29,7 @@ UNIFIED_SOURCES += [
|
|||
'RenderTextureHostOGL.cpp',
|
||||
'RenderThread.cpp',
|
||||
'WebRenderAPI.cpp',
|
||||
'WebRenderTypes.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
|
|
|
@ -958,8 +958,7 @@ pub unsafe extern "C" fn wr_api_set_display_list(
|
|||
pipeline_id: WrPipelineId,
|
||||
content_size: LayoutSize,
|
||||
dl_descriptor: BuiltDisplayListDescriptor,
|
||||
dl_data: *mut u8,
|
||||
dl_size: usize,
|
||||
dl_data: &mut WrVecU8,
|
||||
resources: &mut ResourceUpdates,
|
||||
) {
|
||||
let resource_updates = mem::replace(resources, ResourceUpdates::new());
|
||||
|
@ -971,10 +970,7 @@ pub unsafe extern "C" fn wr_api_set_display_list(
|
|||
// but I suppose it is a good default.
|
||||
let preserve_frame_state = true;
|
||||
|
||||
let dl_slice = make_slice(dl_data, dl_size);
|
||||
let mut dl_vec = Vec::new();
|
||||
// XXX: see if we can get rid of the copy here
|
||||
dl_vec.extend_from_slice(dl_slice);
|
||||
let dl_vec = dl_data.flush_into_vec();
|
||||
let dl = BuiltDisplayList::from_data(dl_vec, dl_descriptor);
|
||||
|
||||
dh.api.set_display_list(
|
||||
|
|
|
@ -1068,8 +1068,7 @@ void wr_api_set_display_list(DocumentHandle *aDh,
|
|||
WrPipelineId aPipelineId,
|
||||
LayoutSize aContentSize,
|
||||
BuiltDisplayListDescriptor aDlDescriptor,
|
||||
uint8_t *aDlData,
|
||||
size_t aDlSize,
|
||||
WrVecU8 *aDlData,
|
||||
ResourceUpdates *aResources)
|
||||
WR_FUNC;
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// |jit-test| --ion-offthread-compile=off
|
||||
|
||||
load(libdir + "asm.js");
|
||||
|
||||
if (!isAsmJSCompilationAvailable())
|
||||
quit(0);
|
||||
|
||||
if (!('oomTest' in this))
|
||||
quit();
|
||||
|
||||
oomTest(
|
||||
function() {
|
||||
eval(`
|
||||
function f(stdlib, foreign, buffer) {
|
||||
"use asm";
|
||||
var i32 = new stdlib.Int32Array(buffer);
|
||||
function set(v) {
|
||||
v=v|0;
|
||||
i32[5] = v;
|
||||
}
|
||||
return set;
|
||||
}
|
||||
`);
|
||||
}
|
||||
);
|
|
@ -739,18 +739,6 @@ JitRuntime::getVMWrapper(const VMFunction& f) const
|
|||
return trampolineCode(p->value());
|
||||
}
|
||||
|
||||
void
|
||||
JitCodeHeader::init(JitCode* jitCode)
|
||||
{
|
||||
jitCode_ = jitCode;
|
||||
|
||||
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
|
||||
// On AMD Bobcat processors that may have eratas, insert a NOP slide to reduce crashes
|
||||
if (CPUInfo::NeedAmdBugWorkaround())
|
||||
memset((char *)&nops_, X86Encoding::OneByteOpcodeID::OP_NOP, sizeof(nops_));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JitCode*
|
||||
JitCode::New(JSContext* cx, uint8_t* code, uint32_t bufferSize, uint32_t headerSize,
|
||||
|
@ -779,10 +767,9 @@ JitCode::New<NoGC>(JSContext* cx, uint8_t* code, uint32_t bufferSize, uint32_t h
|
|||
void
|
||||
JitCode::copyFrom(MacroAssembler& masm)
|
||||
{
|
||||
// Store the JitCode pointer in the JitCodeHeader so we can recover the
|
||||
// gcthing from relocation tables.
|
||||
JitCodeHeader::FromExecutable(code_)->init(this);
|
||||
|
||||
// Store the JitCode pointer right before the code buffer, so we can
|
||||
// recover the gcthing from relocation tables.
|
||||
*(JitCode**)(code_ - sizeof(JitCode*)) = this;
|
||||
insnSize_ = masm.instructionsSize();
|
||||
masm.executableCopy(code_);
|
||||
|
||||
|
|
|
@ -29,30 +29,10 @@ class MacroAssembler;
|
|||
class PatchableBackedge;
|
||||
class IonBuilder;
|
||||
class IonICEntry;
|
||||
class JitCode;
|
||||
|
||||
typedef Vector<JSObject*, 4, JitAllocPolicy> ObjectVector;
|
||||
typedef Vector<TraceLoggerEvent, 0, SystemAllocPolicy> TraceLoggerEventVector;
|
||||
|
||||
// Header at start of raw code buffer
|
||||
struct JitCodeHeader
|
||||
{
|
||||
// Link back to corresponding gcthing
|
||||
JitCode* jitCode_;
|
||||
|
||||
// !!! NOTE !!!
|
||||
// If we are running on AMD Bobcat, insert a NOP-slide at end of the JitCode
|
||||
// header so we can try to recover when the CPU screws up the branch landing
|
||||
// site. See Bug 1281759.
|
||||
void* nops_;
|
||||
|
||||
void init(JitCode* jitCode);
|
||||
|
||||
static JitCodeHeader* FromExecutable(uint8_t* buffer) {
|
||||
return (JitCodeHeader*)(buffer - sizeof(JitCodeHeader));
|
||||
}
|
||||
};
|
||||
|
||||
class JitCode : public gc::TenuredCell
|
||||
{
|
||||
protected:
|
||||
|
@ -149,7 +129,7 @@ class JitCode : public gc::TenuredCell
|
|||
void copyFrom(MacroAssembler& masm);
|
||||
|
||||
static JitCode* FromExecutable(uint8_t* buffer) {
|
||||
JitCode* code = JitCodeHeader::FromExecutable(buffer)->jitCode_;
|
||||
JitCode* code = *(JitCode**)(buffer - sizeof(JitCode*));
|
||||
MOZ_ASSERT(code->raw() == buffer);
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -540,6 +540,23 @@ MIRTypeToTag(MIRType type)
|
|||
return JSVAL_TYPE_TO_TAG(ValueTypeFromMIRType(type));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
MIRTypeToSize(MIRType type)
|
||||
{
|
||||
switch (type) {
|
||||
case MIRType::Int32:
|
||||
return 4;
|
||||
case MIRType::Int64:
|
||||
return 8;
|
||||
case MIRType::Float32:
|
||||
return 4;
|
||||
case MIRType::Double:
|
||||
return 8;
|
||||
default:
|
||||
MOZ_CRASH("MIRTypeToSize - unhandled case");
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char*
|
||||
StringFromMIRType(MIRType type)
|
||||
{
|
||||
|
|
|
@ -23,35 +23,27 @@ Linker::newCode(JSContext* cx, CodeKind kind, bool hasPatchableBackedges /* = fa
|
|||
if (masm.oom())
|
||||
return fail(cx);
|
||||
|
||||
static const size_t ExecutableAllocatorAlignment = sizeof(void*);
|
||||
static_assert(CodeAlignment >= ExecutableAllocatorAlignment,
|
||||
"Unexpected alignment requirements");
|
||||
|
||||
// We require enough bytes for the code, header, and worst-case alignment padding.
|
||||
size_t bytesNeeded = masm.bytesNeeded() +
|
||||
sizeof(JitCodeHeader) +
|
||||
(CodeAlignment - ExecutableAllocatorAlignment);
|
||||
ExecutablePool* pool;
|
||||
size_t bytesNeeded = masm.bytesNeeded() + sizeof(JitCode*) + CodeAlignment;
|
||||
if (bytesNeeded >= MAX_BUFFER_SIZE)
|
||||
return fail(cx);
|
||||
|
||||
// ExecutableAllocator requires bytesNeeded to be aligned.
|
||||
bytesNeeded = AlignBytes(bytesNeeded, ExecutableAllocatorAlignment);
|
||||
// ExecutableAllocator requires bytesNeeded to be word-size aligned.
|
||||
bytesNeeded = AlignBytes(bytesNeeded, sizeof(void*));
|
||||
|
||||
ExecutableAllocator& execAlloc = hasPatchableBackedges
|
||||
? cx->runtime()->jitRuntime()->backedgeExecAlloc()
|
||||
: cx->runtime()->jitRuntime()->execAlloc();
|
||||
|
||||
ExecutablePool* pool;
|
||||
uint8_t* result = (uint8_t*)execAlloc.alloc(cx, bytesNeeded, &pool, kind);
|
||||
if (!result)
|
||||
return fail(cx);
|
||||
|
||||
// The JitCodeHeader will be stored right before the code buffer.
|
||||
uint8_t* codeStart = result + sizeof(JitCodeHeader);
|
||||
// The JitCode pointer will be stored right before the code buffer.
|
||||
uint8_t* codeStart = result + sizeof(JitCode*);
|
||||
|
||||
// Bump the code up to a nice alignment.
|
||||
codeStart = (uint8_t*)AlignBytes((uintptr_t)codeStart, CodeAlignment);
|
||||
MOZ_ASSERT(codeStart + masm.bytesNeeded() <= result + bytesNeeded);
|
||||
uint32_t headerSize = codeStart - result;
|
||||
JitCode* code = JitCode::New<allowGC>(cx, codeStart, bytesNeeded - headerSize,
|
||||
headerSize, pool, kind);
|
||||
|
|
|
@ -1471,16 +1471,24 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
DEFINED_ON(arm);
|
||||
|
||||
// wasm specific methods, used in both the wasm baseline compiler and ion.
|
||||
void wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86, x64, arm, mips32, mips64);
|
||||
void wasmTruncateDoubleToInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86_shared, arm, mips_shared);
|
||||
void outOfLineWasmTruncateDoubleToInt32(FloatRegister input, bool isUnsigned, wasm::BytecodeOffset off, Label* rejoin) DEFINED_ON(x86_shared);
|
||||
void wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry) PER_ARCH;
|
||||
void wasmTruncateDoubleToInt32(FloatRegister input, Register output, Label* oolEntry) PER_SHARED_ARCH;
|
||||
void outOfLineWasmTruncateDoubleToInt32(FloatRegister input, bool isUnsigned,
|
||||
wasm::BytecodeOffset off, Label* rejoin)
|
||||
DEFINED_ON(x86_shared);
|
||||
|
||||
void wasmTruncateFloat32ToUInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86, x64, arm, mips32, mips64);
|
||||
void wasmTruncateFloat32ToInt32(FloatRegister input, Register output, Label* oolEntry) DEFINED_ON(x86_shared, arm, mips_shared);
|
||||
void outOfLineWasmTruncateFloat32ToInt32(FloatRegister input, bool isUnsigned, wasm::BytecodeOffset off, Label* rejoin) DEFINED_ON(x86_shared);
|
||||
void wasmTruncateFloat32ToUInt32(FloatRegister input, Register output, Label* oolEntry) PER_ARCH;
|
||||
void wasmTruncateFloat32ToInt32(FloatRegister input, Register output, Label* oolEntry) PER_SHARED_ARCH;
|
||||
void outOfLineWasmTruncateFloat32ToInt32(FloatRegister input, bool isUnsigned,
|
||||
wasm::BytecodeOffset off, Label* rejoin)
|
||||
DEFINED_ON(x86_shared);
|
||||
|
||||
void outOfLineWasmTruncateDoubleToInt64(FloatRegister input, bool isUnsigned, wasm::BytecodeOffset off, Label* rejoin) DEFINED_ON(x86_shared);
|
||||
void outOfLineWasmTruncateFloat32ToInt64(FloatRegister input, bool isUnsigned, wasm::BytecodeOffset off, Label* rejoin) DEFINED_ON(x86_shared);
|
||||
void outOfLineWasmTruncateDoubleToInt64(FloatRegister input, bool isUnsigned,
|
||||
wasm::BytecodeOffset off, Label* rejoin)
|
||||
DEFINED_ON(x86_shared);
|
||||
void outOfLineWasmTruncateFloat32ToInt64(FloatRegister input, bool isUnsigned,
|
||||
wasm::BytecodeOffset off, Label* rejoin)
|
||||
DEFINED_ON(x86_shared);
|
||||
|
||||
// This function takes care of loading the callee's TLS and pinned regs but
|
||||
// it is the caller's responsibility to save/restore TLS or pinned regs.
|
||||
|
|
|
@ -932,6 +932,33 @@ MacroAssembler::comment(const char* msg)
|
|||
Assembler::comment(msg);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// wasm support
|
||||
|
||||
void
|
||||
MacroAssembler::wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::wasmTruncateDoubleToInt32(FloatRegister input, Register output, Label* oolEntry)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::wasmTruncateFloat32ToUInt32(FloatRegister input, Register output, Label* oolEntry)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::wasmTruncateFloat32ToInt32(FloatRegister input, Register output, Label* oolEntry)
|
||||
{
|
||||
MOZ_CRASH("NYI");
|
||||
}
|
||||
|
||||
//}}} check_macroassembler_style
|
||||
|
||||
} // namespace jit
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -897,6 +897,8 @@ class FunctionCompiler
|
|||
checkOffsetAndAlignmentAndBounds(access, &base);
|
||||
load = MWasmLoad::New(alloc(), memoryBase, base, *access, ToMIRType(result));
|
||||
}
|
||||
if (!load)
|
||||
return nullptr;
|
||||
curBlock_->add(load);
|
||||
return load;
|
||||
}
|
||||
|
@ -917,6 +919,8 @@ class FunctionCompiler
|
|||
checkOffsetAndAlignmentAndBounds(access, &base);
|
||||
store = MWasmStore::New(alloc(), memoryBase, base, *access, v);
|
||||
}
|
||||
if (!store)
|
||||
return;
|
||||
curBlock_->add(store);
|
||||
}
|
||||
|
||||
|
@ -941,6 +945,8 @@ class FunctionCompiler
|
|||
MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
|
||||
MInstruction* cas = MWasmCompareExchangeHeap::New(alloc(), bytecodeOffset(), memoryBase,
|
||||
base, *access, oldv, newv, tlsPointer_);
|
||||
if (!cas)
|
||||
return nullptr;
|
||||
curBlock_->add(cas);
|
||||
|
||||
if (isSmallerAccessForI64(result, access)) {
|
||||
|
@ -968,6 +974,8 @@ class FunctionCompiler
|
|||
MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
|
||||
MInstruction* xchg = MWasmAtomicExchangeHeap::New(alloc(), bytecodeOffset(), memoryBase,
|
||||
base, *access, value, tlsPointer_);
|
||||
if (!xchg)
|
||||
return nullptr;
|
||||
curBlock_->add(xchg);
|
||||
|
||||
if (isSmallerAccessForI64(result, access)) {
|
||||
|
@ -995,6 +1003,8 @@ class FunctionCompiler
|
|||
MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
|
||||
MInstruction* binop = MWasmAtomicBinopHeap::New(alloc(), bytecodeOffset(), op, memoryBase,
|
||||
base, *access, value, tlsPointer_);
|
||||
if (!binop)
|
||||
return nullptr;
|
||||
curBlock_->add(binop);
|
||||
|
||||
if (isSmallerAccessForI64(result, access)) {
|
||||
|
|
|
@ -109,6 +109,8 @@ class VerifyToolsMixin(object):
|
|||
repo_tests_path = os.path.join("testing", "web-platform", "tests")
|
||||
tests_path = os.path.join("tests", "web-platform", "tests")
|
||||
for (type, path, test) in man:
|
||||
if type not in ["testharness", "reftest", "wdspec"]:
|
||||
continue
|
||||
repo_path = os.path.join(repo_tests_path, path)
|
||||
# manifest paths use os.sep (like backslash on Windows) but
|
||||
# automation-relevance uses posixpath.sep
|
||||
|
|
|
@ -9,4 +9,5 @@ support-files =
|
|||
[browser_host_name.js]
|
||||
[browser_request_summary.js]
|
||||
[browser_show_dialog.js]
|
||||
skip-if = os == 'win' && debug # bug 1418385
|
||||
[browser_total.js]
|
||||
|
|
|
@ -2167,6 +2167,10 @@ nsWindow::UserActivity()
|
|||
if (mIdleService) {
|
||||
mIdleService->ResetIdleTimeOut(0);
|
||||
}
|
||||
|
||||
if (FindTopLevel() != nsWindow::TopWindow()) {
|
||||
BringToFront();
|
||||
}
|
||||
}
|
||||
|
||||
TextEventDispatcherListener*
|
||||
|
|
|
@ -55,6 +55,23 @@ public:
|
|||
|
||||
void AsyncWaitCompleted();
|
||||
|
||||
struct StreamData
|
||||
{
|
||||
void Initialize(nsIInputStream* aStream)
|
||||
{
|
||||
mStream = aStream;
|
||||
mAsyncStream = do_QueryInterface(aStream);
|
||||
mSeekableStream = do_QueryInterface(aStream);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
|
||||
// This can be null.
|
||||
nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
|
||||
// This can be null.
|
||||
nsCOMPtr<nsISeekableStream> mSeekableStream;
|
||||
};
|
||||
|
||||
private:
|
||||
~nsMultiplexInputStream()
|
||||
{
|
||||
|
@ -62,7 +79,7 @@ private:
|
|||
|
||||
// This method updates mSeekableStreams, mIPCSerializableStreams,
|
||||
// mCloneableStreams and mAsyncInputStreams values.
|
||||
void UpdateQIMap(nsIInputStream* aStream, int32_t aCount);
|
||||
void UpdateQIMap(StreamData& aStream, int32_t aCount);
|
||||
|
||||
struct MOZ_STACK_CLASS ReadSegmentsState
|
||||
{
|
||||
|
@ -83,7 +100,9 @@ private:
|
|||
bool IsAsyncInputStream() const;
|
||||
|
||||
Mutex mLock; // Protects access to all data members.
|
||||
nsTArray<nsCOMPtr<nsIInputStream>> mStreams;
|
||||
|
||||
nsTArray<StreamData> mStreams;
|
||||
|
||||
uint32_t mCurrentStream;
|
||||
bool mStartedReadingCurrent;
|
||||
nsresult mStatus;
|
||||
|
@ -121,19 +140,20 @@ NS_IMPL_CI_INTERFACE_GETTER(nsMultiplexInputStream,
|
|||
nsISeekableStream)
|
||||
|
||||
static nsresult
|
||||
AvailableMaybeSeek(nsIInputStream* aStream, uint64_t* aResult)
|
||||
AvailableMaybeSeek(nsMultiplexInputStream::StreamData& aStream,
|
||||
uint64_t* aResult)
|
||||
{
|
||||
nsresult rv = aStream->Available(aResult);
|
||||
nsresult rv = aStream.mStream->Available(aResult);
|
||||
if (rv == NS_BASE_STREAM_CLOSED) {
|
||||
// Blindly seek to the current position if Available() returns
|
||||
// NS_BASE_STREAM_CLOSED.
|
||||
// If nsIFileInputStream is closed in Read() due to CLOSE_ON_EOF flag,
|
||||
// Seek() could reopen the file if REOPEN_ON_REWIND flag is set.
|
||||
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(aStream);
|
||||
if (seekable) {
|
||||
nsresult rvSeek = seekable->Seek(nsISeekableStream::NS_SEEK_CUR, 0);
|
||||
if (aStream.mSeekableStream) {
|
||||
nsresult rvSeek =
|
||||
aStream.mSeekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, 0);
|
||||
if (NS_SUCCEEDED(rvSeek)) {
|
||||
rv = aStream->Available(aResult);
|
||||
rv = aStream.mStream->Available(aResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,11 +200,21 @@ NS_IMETHODIMP
|
|||
nsMultiplexInputStream::AppendStream(nsIInputStream* aStream)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if (!mStreams.AppendElement(aStream)) {
|
||||
|
||||
StreamData* streamData = mStreams.AppendElement();
|
||||
if (NS_WARN_IF(!streamData)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
UpdateQIMap(aStream, 1);
|
||||
streamData->Initialize(aStream);
|
||||
|
||||
UpdateQIMap(*streamData, 1);
|
||||
|
||||
if (mStatus == NS_BASE_STREAM_CLOSED) {
|
||||
// We were closed, but now we have more data to read.
|
||||
mStatus = NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -192,16 +222,23 @@ NS_IMETHODIMP
|
|||
nsMultiplexInputStream::InsertStream(nsIInputStream* aStream, uint32_t aIndex)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if (!mStreams.InsertElementAt(aIndex, aStream)) {
|
||||
|
||||
StreamData* streamData = mStreams.InsertElementAt(aIndex);
|
||||
if (NS_WARN_IF(!streamData)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
streamData->Initialize(aStream);
|
||||
|
||||
if (mCurrentStream > aIndex ||
|
||||
(mCurrentStream == aIndex && mStartedReadingCurrent)) {
|
||||
++mCurrentStream;
|
||||
} else if (mStatus == NS_BASE_STREAM_CLOSED) {
|
||||
// We were closed, but now we have more data to read.
|
||||
mStatus = NS_OK;
|
||||
}
|
||||
|
||||
UpdateQIMap(aStream, 1);
|
||||
UpdateQIMap(*streamData, 1);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -229,12 +266,15 @@ NS_IMETHODIMP
|
|||
nsMultiplexInputStream::GetStream(uint32_t aIndex, nsIInputStream** aResult)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
*aResult = mStreams.SafeElementAt(aIndex, nullptr);
|
||||
if (NS_WARN_IF(!*aResult)) {
|
||||
|
||||
if (aIndex >= mStreams.Length()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult);
|
||||
StreamData& streamData = mStreams.ElementAt(aIndex);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = streamData.mStream;
|
||||
stream.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -248,7 +288,7 @@ nsMultiplexInputStream::Close()
|
|||
|
||||
uint32_t len = mStreams.Length();
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
nsresult rv2 = mStreams[i]->Close();
|
||||
nsresult rv2 = mStreams[i].mStream->Close();
|
||||
// We still want to close all streams, but we should return an error
|
||||
if (NS_FAILED(rv2)) {
|
||||
rv = rv2;
|
||||
|
@ -261,24 +301,57 @@ nsMultiplexInputStream::Close()
|
|||
NS_IMETHODIMP
|
||||
nsMultiplexInputStream::Available(uint64_t* aResult)
|
||||
{
|
||||
*aResult = 0;
|
||||
|
||||
MutexAutoLock lock(mLock);
|
||||
if (NS_FAILED(mStatus)) {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
uint64_t avail = 0;
|
||||
nsresult rv = NS_BASE_STREAM_CLOSED;
|
||||
|
||||
uint32_t len = mStreams.Length();
|
||||
for (uint32_t i = mCurrentStream; i < len; i++) {
|
||||
uint64_t streamAvail;
|
||||
mStatus = AvailableMaybeSeek(mStreams[i], &streamAvail);
|
||||
if (NS_WARN_IF(NS_FAILED(mStatus))) {
|
||||
rv = AvailableMaybeSeek(mStreams[i], &streamAvail);
|
||||
if (rv == NS_BASE_STREAM_CLOSED) {
|
||||
// If a stream is closed, we continue with the next one.
|
||||
// If this is the last stream, we want to return this error code.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mStatus = rv;
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
// If the current stream is async, we have to return what we have so far
|
||||
// without processing the following streams. This is needed because
|
||||
// ::Available should return only what is currently available. In case of an
|
||||
// nsIAsyncInputStream, we have to call AsyncWait() in order to read more.
|
||||
if (mStreams[i].mAsyncStream) {
|
||||
avail += streamAvail;
|
||||
break;
|
||||
}
|
||||
|
||||
if (streamAvail == 0) {
|
||||
// Nothing to read for this stream. Let's move to the next one.
|
||||
continue;
|
||||
}
|
||||
|
||||
avail += streamAvail;
|
||||
}
|
||||
*aResult = avail;
|
||||
return NS_OK;
|
||||
|
||||
// We still have something to read. We don't want to return an error code yet.
|
||||
if (avail) {
|
||||
*aResult = avail;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Let's propagate the last error message.
|
||||
mStatus = rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -303,7 +376,7 @@ nsMultiplexInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* aResult)
|
|||
uint32_t len = mStreams.Length();
|
||||
while (mCurrentStream < len && aCount) {
|
||||
uint32_t read;
|
||||
rv = mStreams[mCurrentStream]->Read(aBuf, aCount, &read);
|
||||
rv = mStreams[mCurrentStream].mStream->Read(aBuf, aCount, &read);
|
||||
|
||||
// XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
|
||||
// (This is a bug in those stream implementations)
|
||||
|
@ -356,7 +429,8 @@ nsMultiplexInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
|||
uint32_t len = mStreams.Length();
|
||||
while (mCurrentStream < len && aCount) {
|
||||
uint32_t read;
|
||||
rv = mStreams[mCurrentStream]->ReadSegments(ReadSegCb, &state, aCount, &read);
|
||||
rv = mStreams[mCurrentStream].mStream->ReadSegments(ReadSegCb, &state,
|
||||
aCount, &read);
|
||||
|
||||
// XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
|
||||
// (This is a bug in those stream implementations)
|
||||
|
@ -416,14 +490,11 @@ nsMultiplexInputStream::IsNonBlocking(bool* aNonBlocking)
|
|||
uint32_t len = mStreams.Length();
|
||||
if (len == 0) {
|
||||
// Claim to be non-blocking, since we won't block the caller.
|
||||
// On the other hand we'll never return NS_BASE_STREAM_WOULD_BLOCK,
|
||||
// so maybe we should claim to be blocking? It probably doesn't
|
||||
// matter in practice.
|
||||
*aNonBlocking = true;
|
||||
return NS_OK;
|
||||
}
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
nsresult rv = mStreams[i]->IsNonBlocking(aNonBlocking);
|
||||
nsresult rv = mStreams[i].mStream->IsNonBlocking(aNonBlocking);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -457,8 +528,7 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
|||
mCurrentStream = 0;
|
||||
}
|
||||
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
|
||||
nsCOMPtr<nsISeekableStream> stream =
|
||||
do_QueryInterface(mStreams[i]);
|
||||
nsCOMPtr<nsISeekableStream> stream = mStreams[i].mSeekableStream;
|
||||
if (!stream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -540,9 +610,6 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
|||
if (aWhence == NS_SEEK_CUR && aOffset > 0) {
|
||||
int64_t remaining = aOffset;
|
||||
for (uint32_t i = mCurrentStream; remaining && i < mStreams.Length(); ++i) {
|
||||
nsCOMPtr<nsISeekableStream> stream =
|
||||
do_QueryInterface(mStreams[i]);
|
||||
|
||||
uint64_t avail;
|
||||
rv = AvailableMaybeSeek(mStreams[i], &avail);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -551,7 +618,7 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
|||
|
||||
int64_t seek = XPCOM_MIN((int64_t)avail, remaining);
|
||||
|
||||
rv = stream->Seek(NS_SEEK_CUR, seek);
|
||||
rv = mStreams[i].mSeekableStream->Seek(NS_SEEK_CUR, seek);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -568,18 +635,15 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
|||
if (aWhence == NS_SEEK_CUR && aOffset < 0) {
|
||||
int64_t remaining = -aOffset;
|
||||
for (uint32_t i = mCurrentStream; remaining && i != (uint32_t)-1; --i) {
|
||||
nsCOMPtr<nsISeekableStream> stream =
|
||||
do_QueryInterface(mStreams[i]);
|
||||
|
||||
int64_t pos;
|
||||
rv = TellMaybeSeek(stream, &pos);
|
||||
rv = TellMaybeSeek(mStreams[i].mSeekableStream, &pos);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
int64_t seek = XPCOM_MIN(pos, remaining);
|
||||
|
||||
rv = stream->Seek(NS_SEEK_CUR, -seek);
|
||||
rv = mStreams[i].mSeekableStream->Seek(NS_SEEK_CUR, -seek);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -605,8 +669,7 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
|||
}
|
||||
int64_t remaining = aOffset;
|
||||
for (uint32_t i = mStreams.Length() - 1; i != (uint32_t)-1; --i) {
|
||||
nsCOMPtr<nsISeekableStream> stream =
|
||||
do_QueryInterface(mStreams[i]);
|
||||
nsCOMPtr<nsISeekableStream> stream = mStreams[i].mSeekableStream;
|
||||
|
||||
// See if all remaining streams should be seeked to end
|
||||
if (remaining == 0) {
|
||||
|
@ -696,13 +759,12 @@ nsMultiplexInputStream::Tell(int64_t* aResult)
|
|||
uint32_t i, last;
|
||||
last = mStartedReadingCurrent ? mCurrentStream + 1 : mCurrentStream;
|
||||
for (i = 0; i < last; ++i) {
|
||||
nsCOMPtr<nsISeekableStream> stream = do_QueryInterface(mStreams[i]);
|
||||
if (NS_WARN_IF(!stream)) {
|
||||
if (NS_WARN_IF(!mStreams[i].mSeekableStream)) {
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
int64_t pos;
|
||||
rv = TellMaybeSeek(stream, &pos);
|
||||
rv = TellMaybeSeek(mStreams[i].mSeekableStream, &pos);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -864,10 +926,8 @@ nsMultiplexInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
|
|||
|
||||
nsTArray<nsCOMPtr<nsIAsyncInputStream>> asyncStreams;
|
||||
for (uint32_t i = mCurrentStream; i < mStreams.Length(); ++i) {
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream =
|
||||
do_QueryInterface(mStreams.SafeElementAt(i, nullptr));
|
||||
if (asyncStream) {
|
||||
asyncStreams.AppendElement(asyncStream);
|
||||
if (mStreams[i].mAsyncStream) {
|
||||
asyncStreams.AppendElement(mStreams[i].mAsyncStream);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -935,7 +995,7 @@ nsMultiplexInputStream::Serialize(InputStreamParams& aParams,
|
|||
streams.SetCapacity(streamCount);
|
||||
for (uint32_t index = 0; index < streamCount; index++) {
|
||||
InputStreamParams childStreamParams;
|
||||
InputStreamHelper::SerializeInputStream(mStreams[index],
|
||||
InputStreamHelper::SerializeInputStream(mStreams[index].mStream,
|
||||
childStreamParams,
|
||||
aFileDescriptors);
|
||||
|
||||
|
@ -997,7 +1057,8 @@ nsMultiplexInputStream::ExpectedSerializedLength()
|
|||
uint64_t expectedLength = 0;
|
||||
uint32_t streamCount = mStreams.Length();
|
||||
for (uint32_t index = 0; index < streamCount; index++) {
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> stream = do_QueryInterface(mStreams[index]);
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> stream =
|
||||
do_QueryInterface(mStreams[index].mStream);
|
||||
if (!stream) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1024,7 +1085,8 @@ nsMultiplexInputStream::GetCloneable(bool* aCloneable)
|
|||
|
||||
uint32_t len = mStreams.Length();
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
nsCOMPtr<nsICloneableInputStream> cis = do_QueryInterface(mStreams[i]);
|
||||
nsCOMPtr<nsICloneableInputStream> cis =
|
||||
do_QueryInterface(mStreams[i].mStream);
|
||||
if (!cis || !cis->GetCloneable()) {
|
||||
*aCloneable = false;
|
||||
return NS_OK;
|
||||
|
@ -1051,7 +1113,8 @@ nsMultiplexInputStream::Clone(nsIInputStream** aClone)
|
|||
nsresult rv;
|
||||
uint32_t len = mStreams.Length();
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
nsCOMPtr<nsICloneableInputStream> substream = do_QueryInterface(mStreams[i]);
|
||||
nsCOMPtr<nsICloneableInputStream> substream =
|
||||
do_QueryInterface(mStreams[i].mStream);
|
||||
if (NS_WARN_IF(!substream)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -1072,30 +1135,32 @@ nsMultiplexInputStream::Clone(nsIInputStream** aClone)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
#define MAYBE_UPDATE_VALUE(x, y) \
|
||||
{ \
|
||||
nsCOMPtr<y> substream = do_QueryInterface(aStream); \
|
||||
if (substream) { \
|
||||
if (aCount == 1) { \
|
||||
++x; \
|
||||
} else if (x > 0) { \
|
||||
--x; \
|
||||
} else { \
|
||||
MOZ_CRASH("A nsIInputStream changed QI map when stored in a nsMultiplexInputStream!"); \
|
||||
} \
|
||||
} \
|
||||
#define MAYBE_UPDATE_VALUE_REAL(x, y) \
|
||||
if (y) { \
|
||||
if (aCount == 1) { \
|
||||
++x; \
|
||||
} else if (x > 0) { \
|
||||
--x; \
|
||||
} else { \
|
||||
MOZ_CRASH("A nsIInputStream changed QI map when stored in a nsMultiplexInputStream!"); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MAYBE_UPDATE_VALUE(x, y) \
|
||||
{ \
|
||||
nsCOMPtr<y> substream = do_QueryInterface(aStream.mStream); \
|
||||
MAYBE_UPDATE_VALUE_REAL(x, substream) \
|
||||
}
|
||||
|
||||
void
|
||||
nsMultiplexInputStream::UpdateQIMap(nsIInputStream* aStream, int32_t aCount)
|
||||
nsMultiplexInputStream::UpdateQIMap(StreamData& aStream, int32_t aCount)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(aCount == -1 || aCount == 1);
|
||||
|
||||
MAYBE_UPDATE_VALUE(mSeekableStreams, nsISeekableStream);
|
||||
MAYBE_UPDATE_VALUE(mIPCSerializableStreams, nsIIPCSerializableInputStream);
|
||||
MAYBE_UPDATE_VALUE(mCloneableStreams, nsICloneableInputStream);
|
||||
MAYBE_UPDATE_VALUE(mAsyncInputStreams, nsIAsyncInputStream);
|
||||
MAYBE_UPDATE_VALUE_REAL(mSeekableStreams, aStream.mSeekableStream)
|
||||
MAYBE_UPDATE_VALUE(mIPCSerializableStreams, nsIIPCSerializableInputStream)
|
||||
MAYBE_UPDATE_VALUE(mCloneableStreams, nsICloneableInputStream)
|
||||
MAYBE_UPDATE_VALUE_REAL(mAsyncInputStreams, aStream.mAsyncStream)
|
||||
}
|
||||
|
||||
#undef MAYBE_UPDATE_VALUE
|
||||
|
|
|
@ -213,3 +213,184 @@ TEST(TestMultiplexInputStream, AsyncWait_withEventTarget_closureOnly) {
|
|||
MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil([&]() { return cb->Called(); }));
|
||||
ASSERT_TRUE(cb->Called());
|
||||
}
|
||||
|
||||
class ClosedStream final : public nsIInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
ClosedStream() {}
|
||||
|
||||
NS_IMETHOD
|
||||
Available(uint64_t* aLength) override
|
||||
{
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override
|
||||
{
|
||||
MOZ_CRASH("This should not be called!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t *aResult) override
|
||||
{
|
||||
MOZ_CRASH("This should not be called!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Close() override { return NS_OK; }
|
||||
|
||||
NS_IMETHOD
|
||||
IsNonBlocking(bool* aNonBlocking) override
|
||||
{
|
||||
*aNonBlocking = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~ClosedStream() = default;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ClosedStream, nsIInputStream)
|
||||
|
||||
class AsyncStream final : public nsIAsyncInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
explicit AsyncStream(int64_t aSize) : mState(eBlocked), mSize(aSize) {}
|
||||
|
||||
void
|
||||
Unblock()
|
||||
{
|
||||
mState = eUnblocked;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Available(uint64_t* aLength) override
|
||||
{
|
||||
*aLength = mState == eBlocked ? 0 : mSize;
|
||||
return mState == eClosed ? NS_BASE_STREAM_CLOSED : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override
|
||||
{
|
||||
MOZ_CRASH("This should not be called!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t *aResult) override
|
||||
{
|
||||
MOZ_CRASH("This should not be called!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Close() override
|
||||
{
|
||||
mState = eClosed;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
IsNonBlocking(bool* aNonBlocking) override
|
||||
{
|
||||
*aNonBlocking = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
AsyncWait(nsIInputStreamCallback* aCallback,
|
||||
uint32_t aFlags, uint32_t aRequestedCount,
|
||||
nsIEventTarget* aEventTarget) override
|
||||
{
|
||||
MOZ_CRASH("This should not be called!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
CloseWithStatus(nsresult aStatus) override
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~AsyncStream() = default;
|
||||
|
||||
enum {
|
||||
eBlocked,
|
||||
eUnblocked,
|
||||
eClosed
|
||||
} mState;
|
||||
|
||||
uint64_t mSize;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(AsyncStream, nsIInputStream, nsIAsyncInputStream)
|
||||
|
||||
TEST(TestMultiplexInputStream, Available) {
|
||||
nsCOMPtr<nsIMultiplexInputStream> multiplexStream =
|
||||
do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
|
||||
|
||||
nsCOMPtr<nsIInputStream> s = do_QueryInterface(multiplexStream);
|
||||
ASSERT_TRUE(!!s);
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> as = do_QueryInterface(multiplexStream);
|
||||
ASSERT_TRUE(!as);
|
||||
|
||||
uint64_t length;
|
||||
|
||||
// The stream returns NS_BASE_STREAM_CLOSED if there are no substreams.
|
||||
nsresult rv = s->Available(&length);
|
||||
ASSERT_EQ(NS_BASE_STREAM_CLOSED, rv);
|
||||
|
||||
rv = multiplexStream->AppendStream(new ClosedStream());
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
|
||||
uint64_t asyncSize = 2;
|
||||
RefPtr<AsyncStream> asyncStream = new AsyncStream(2);
|
||||
rv = multiplexStream->AppendStream(asyncStream);
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
|
||||
nsCString buffer;
|
||||
buffer.Assign("World!!!");
|
||||
|
||||
nsCOMPtr<nsIInputStream> stringStream;
|
||||
rv = NS_NewCStringInputStream(getter_AddRefs(stringStream), buffer);
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
|
||||
rv = multiplexStream->AppendStream(stringStream);
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
|
||||
// Now we are async.
|
||||
as = do_QueryInterface(multiplexStream);
|
||||
ASSERT_TRUE(!!as);
|
||||
|
||||
// Available should skip the closed stream and return 0 because the
|
||||
// asyncStream returns 0 and it's async.
|
||||
rv = s->Available(&length);
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
ASSERT_EQ((uint64_t)0, length);
|
||||
|
||||
asyncStream->Unblock();
|
||||
|
||||
// Now we should return only the size of the async stream because we don't
|
||||
// know when this is completed.
|
||||
rv = s->Available(&length);
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
ASSERT_EQ(asyncSize, length);
|
||||
|
||||
asyncStream->Close();
|
||||
|
||||
rv = s->Available(&length);
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
ASSERT_EQ(buffer.Length(), length);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче