Merge m-c to b2g-inbound

This commit is contained in:
Wes Kocher 2014-04-22 19:59:02 -07:00
commit d6ab60ebc2
38 changed files with 1459 additions and 705 deletions

View File

@ -521,7 +521,11 @@ AudioInitTask::Run()
MOZ_ASSERT(mThread);
if (NS_IsMainThread()) {
mThread->Shutdown(); // can't Shutdown from the thread itself, darn
mThread = nullptr;
// Don't null out mThread!
// See bug 999104. We must hold a ref to the thread across Dispatch()
// since the internal mThread ref could be released while processing
// the Dispatch(), and Dispatch/PutEvent itself doesn't hold a ref; it
// assumes the caller does.
return NS_OK;
}

View File

@ -445,6 +445,7 @@ public:
// Can't add 'this' as the event to run, since mThread may not be set yet
nsresult rv = NS_NewNamedThread("CubebInit", getter_AddRefs(mThread));
if (NS_SUCCEEDED(rv)) {
// Note: event must not null out mThread!
rv = mThread->Dispatch(this, NS_DISPATCH_NORMAL);
}
return rv;

View File

@ -25,7 +25,7 @@ const Ci = SpecialPowers.Ci;
// not enabled by default yet.
SimpleTest.waitForExplicitFinish();
var policy = setupPolicy();
var policy;
SpecialPowers.pushPrefEnv({'set': [["beacon.enabled", true]]}, beginTest);
@ -88,7 +88,12 @@ function teardownPolicy() {
}
function beginTest() {
navigator.sendBeacon(beaconUrl, "bacon would have been a better name than beacon");
policy = setupPolicy();
// Make sure to hit the event loop here in order to ensure that nsContentPolicy
// has been notified of the newly registered policy.
SimpleTest.executeSoon(function() {
navigator.sendBeacon(beaconUrl, "bacon would have been a better name than beacon");
});
}
</script>

View File

@ -1077,7 +1077,7 @@ nsresult AppCallbacks::CreateBrowserWindow(uint32_t aChromeFlags,
// the interface to return and one addref, which we assume will be
// immediately released
CallQueryInterface(static_cast<nsIWebBrowserChrome*>(chrome), aNewWindow);
*aNewWindow = static_cast<nsIWebBrowserChrome*>(chrome);
// now an extra addref; the window owns itself (to be released by
// WebBrowserChromeUI::Destroy)
NS_ADDREF(*aNewWindow);

View File

@ -13,6 +13,20 @@
#include "js/RootingAPI.h"
#include "js/Value.h"
typedef enum JSGCMode {
/* Perform only global GCs. */
JSGC_MODE_GLOBAL = 0,
/* Perform per-compartment GCs until too much garbage has accumulated. */
JSGC_MODE_COMPARTMENT = 1,
/*
* Collect in short time slices rather than all at once. Implies
* JSGC_MODE_COMPARTMENT.
*/
JSGC_MODE_INCREMENTAL = 2
} JSGCMode;
namespace JS {
#define GCREASONS(D) \

View File

@ -6,17 +6,24 @@
#include "gc/Tracer.h"
#include "mozilla/DebugOnly.h"
#include "jsapi.h"
#include "jsfun.h"
#include "jsgc.h"
#include "jsprf.h"
#include "jsscript.h"
#include "jsutil.h"
#include "NamespaceImports.h"
#include "gc/GCInternals.h"
#include "gc/Marking.h"
#include "jsgcinlines.h"
using namespace js;
using namespace js::gc;
using mozilla::DebugOnly;
JS_PUBLIC_API(void)
JS_CallValueTracer(JSTracer *trc, Value *valuep, const char *name)
@ -326,3 +333,342 @@ JSTracer::tracingLocation(void **thingp)
return realLocation_ ? (void **)realLocation_ : thingp;
}
#endif
bool
MarkStack::init(JSGCMode gcMode)
{
setBaseCapacity(gcMode);
JS_ASSERT(!stack_);
uintptr_t *newStack = js_pod_malloc<uintptr_t>(baseCapacity_);
if (!newStack)
return false;
setStack(newStack, 0, baseCapacity_);
return true;
}
void
MarkStack::setBaseCapacity(JSGCMode mode)
{
switch (mode) {
case JSGC_MODE_GLOBAL:
case JSGC_MODE_COMPARTMENT:
baseCapacity_ = NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY;
break;
case JSGC_MODE_INCREMENTAL:
baseCapacity_ = INCREMENTAL_MARK_STACK_BASE_CAPACITY;
break;
default:
MOZ_ASSUME_UNREACHABLE("bad gc mode");
}
if (baseCapacity_ > maxCapacity_)
baseCapacity_ = maxCapacity_;
}
void
MarkStack::setMaxCapacity(size_t maxCapacity)
{
JS_ASSERT(isEmpty());
maxCapacity_ = maxCapacity;
if (baseCapacity_ > maxCapacity_)
baseCapacity_ = maxCapacity_;
reset();
}
void
MarkStack::reset()
{
if (capacity() == baseCapacity_) {
// No size change; keep the current stack.
setStack(stack_, 0, baseCapacity_);
return;
}
uintptr_t *newStack = (uintptr_t *)js_realloc(stack_, sizeof(uintptr_t) * baseCapacity_);
if (!newStack) {
// If the realloc fails, just keep using the existing stack; it's
// not ideal but better than failing.
newStack = stack_;
baseCapacity_ = capacity();
}
setStack(newStack, 0, baseCapacity_);
}
bool
MarkStack::enlarge(unsigned count)
{
size_t newCapacity = Min(maxCapacity_, capacity() * 2);
if (newCapacity < capacity() + count)
return false;
size_t tosIndex = position();
uintptr_t *newStack = (uintptr_t *)js_realloc(stack_, sizeof(uintptr_t) * newCapacity);
if (!newStack)
return false;
setStack(newStack, tosIndex, newCapacity);
return true;
}
void
MarkStack::setGCMode(JSGCMode gcMode)
{
// The mark stack won't be resized until the next call to reset(), but
// that will happen at the end of the next GC.
setBaseCapacity(gcMode);
}
size_t
MarkStack::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
return mallocSizeOf(stack_);
}
/*
* DoNotTraceWeakMaps: the GC is recomputing the liveness of WeakMap entries,
* so we delay visting entries.
*/
GCMarker::GCMarker(JSRuntime *rt)
: JSTracer(rt, nullptr, DoNotTraceWeakMaps),
stack(size_t(-1)),
color(BLACK),
unmarkedArenaStackTop(nullptr),
markLaterArenas(0),
grayBufferState(GRAY_BUFFER_UNUSED),
started(false)
{
}
bool
GCMarker::init(JSGCMode gcMode)
{
return stack.init(gcMode);
}
void
GCMarker::start()
{
JS_ASSERT(!started);
started = true;
color = BLACK;
JS_ASSERT(!unmarkedArenaStackTop);
JS_ASSERT(markLaterArenas == 0);
}
void
GCMarker::stop()
{
JS_ASSERT(isDrained());
JS_ASSERT(started);
started = false;
JS_ASSERT(!unmarkedArenaStackTop);
JS_ASSERT(markLaterArenas == 0);
/* Free non-ballast stack memory. */
stack.reset();
resetBufferedGrayRoots();
grayBufferState = GRAY_BUFFER_UNUSED;
}
void
GCMarker::reset()
{
color = BLACK;
stack.reset();
JS_ASSERT(isMarkStackEmpty());
while (unmarkedArenaStackTop) {
ArenaHeader *aheader = unmarkedArenaStackTop;
JS_ASSERT(aheader->hasDelayedMarking);
JS_ASSERT(markLaterArenas);
unmarkedArenaStackTop = aheader->getNextDelayedMarking();
aheader->unsetDelayedMarking();
aheader->markOverflow = 0;
aheader->allocatedDuringIncremental = 0;
markLaterArenas--;
}
JS_ASSERT(isDrained());
JS_ASSERT(!markLaterArenas);
}
void
GCMarker::markDelayedChildren(ArenaHeader *aheader)
{
if (aheader->markOverflow) {
bool always = aheader->allocatedDuringIncremental;
aheader->markOverflow = 0;
for (CellIterUnderGC i(aheader); !i.done(); i.next()) {
Cell *t = i.getCell();
if (always || t->isMarked()) {
t->markIfUnmarked();
JS_TraceChildren(this, t, MapAllocToTraceKind(aheader->getAllocKind()));
}
}
} else {
JS_ASSERT(aheader->allocatedDuringIncremental);
PushArena(this, aheader);
}
aheader->allocatedDuringIncremental = 0;
/*
* Note that during an incremental GC we may still be allocating into
* aheader. However, prepareForIncrementalGC sets the
* allocatedDuringIncremental flag if we continue marking.
*/
}
bool
GCMarker::markDelayedChildren(SliceBudget &budget)
{
gcstats::MaybeAutoPhase ap;
if (runtime()->gcIncrementalState == MARK)
ap.construct(runtime()->gcStats, gcstats::PHASE_MARK_DELAYED);
JS_ASSERT(unmarkedArenaStackTop);
do {
/*
* If marking gets delayed at the same arena again, we must repeat
* marking of its things. For that we pop arena from the stack and
* clear its hasDelayedMarking flag before we begin the marking.
*/
ArenaHeader *aheader = unmarkedArenaStackTop;
JS_ASSERT(aheader->hasDelayedMarking);
JS_ASSERT(markLaterArenas);
unmarkedArenaStackTop = aheader->getNextDelayedMarking();
aheader->unsetDelayedMarking();
markLaterArenas--;
markDelayedChildren(aheader);
budget.step(150);
if (budget.isOverBudget())
return false;
} while (unmarkedArenaStackTop);
JS_ASSERT(!markLaterArenas);
return true;
}
#ifdef DEBUG
void
GCMarker::checkZone(void *p)
{
JS_ASSERT(started);
DebugOnly<Cell *> cell = static_cast<Cell *>(p);
JS_ASSERT_IF(cell->isTenured(), cell->tenuredZone()->isCollecting());
}
#endif
bool
GCMarker::hasBufferedGrayRoots() const
{
return grayBufferState == GRAY_BUFFER_OK;
}
void
GCMarker::startBufferingGrayRoots()
{
JS_ASSERT(grayBufferState == GRAY_BUFFER_UNUSED);
grayBufferState = GRAY_BUFFER_OK;
for (GCZonesIter zone(runtime()); !zone.done(); zone.next())
JS_ASSERT(zone->gcGrayRoots.empty());
JS_ASSERT(!callback);
callback = GrayCallback;
JS_ASSERT(IS_GC_MARKING_TRACER(this));
}
void
GCMarker::endBufferingGrayRoots()
{
JS_ASSERT(callback == GrayCallback);
callback = nullptr;
JS_ASSERT(IS_GC_MARKING_TRACER(this));
JS_ASSERT(grayBufferState == GRAY_BUFFER_OK ||
grayBufferState == GRAY_BUFFER_FAILED);
}
void
GCMarker::resetBufferedGrayRoots()
{
for (GCZonesIter zone(runtime()); !zone.done(); zone.next())
zone->gcGrayRoots.clearAndFree();
}
void
GCMarker::markBufferedGrayRoots(JS::Zone *zone)
{
JS_ASSERT(grayBufferState == GRAY_BUFFER_OK);
JS_ASSERT(zone->isGCMarkingGray());
for (GrayRoot *elem = zone->gcGrayRoots.begin(); elem != zone->gcGrayRoots.end(); elem++) {
#ifdef DEBUG
setTracingDetails(elem->debugPrinter, elem->debugPrintArg, elem->debugPrintIndex);
#endif
void *tmp = elem->thing;
setTracingLocation((void *)&elem->thing);
MarkKind(this, &tmp, elem->kind);
JS_ASSERT(tmp == elem->thing);
}
}
void
GCMarker::appendGrayRoot(void *thing, JSGCTraceKind kind)
{
JS_ASSERT(started);
if (grayBufferState == GRAY_BUFFER_FAILED)
return;
GrayRoot root(thing, kind);
#ifdef DEBUG
root.debugPrinter = debugPrinter();
root.debugPrintArg = debugPrintArg();
root.debugPrintIndex = debugPrintIndex();
#endif
Zone *zone = static_cast<Cell *>(thing)->tenuredZone();
if (zone->isCollecting()) {
zone->maybeAlive = true;
if (!zone->gcGrayRoots.append(root)) {
resetBufferedGrayRoots();
grayBufferState = GRAY_BUFFER_FAILED;
}
}
}
void
GCMarker::GrayCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind)
{
JS_ASSERT(thingp);
JS_ASSERT(*thingp);
GCMarker *gcmarker = static_cast<GCMarker *>(trc);
gcmarker->appendGrayRoot(*thingp, kind);
}
size_t
GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
size_t size = stack.sizeOfExcludingThis(mallocSizeOf);
for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next())
size += zone->gcGrayRoots.sizeOfExcludingThis(mallocSizeOf);
return size;
}
void
js::SetMarkStackLimit(JSRuntime *rt, size_t limit)
{
JS_ASSERT(!rt->isHeapBusy());
AutoStopVerifyingBarriers pauseVerification(rt, false);
rt->gcMarker.setMaxCapacity(limit);
}

View File

@ -7,6 +7,301 @@
#ifndef js_Tracer_h
#define js_Tracer_h
#include "mozilla/DebugOnly.h"
#include "js/GCAPI.h"
#include "js/SliceBudget.h"
#include "js/TracingAPI.h"
namespace js {
class GCMarker;
class ObjectImpl;
namespace gc {
class ArenaHeader;
}
namespace jit {
class JitCode;
}
namespace types {
class TypeObject;
}
static const size_t NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY = 4096;
static const size_t INCREMENTAL_MARK_STACK_BASE_CAPACITY = 32768;
/*
* When the native stack is low, the GC does not call JS_TraceChildren to mark
* the reachable "children" of the thing. Rather the thing is put aside and
* JS_TraceChildren is called later with more space on the C stack.
*
* To implement such delayed marking of the children with minimal overhead for
* the normal case of sufficient native stack, the code adds a field per arena.
* The field markingDelay->link links all arenas with delayed things into a
* stack list with the pointer to stack top in GCMarker::unmarkedArenaStackTop.
* GCMarker::delayMarkingChildren adds arenas to the stack as necessary while
* markDelayedChildren pops the arenas from the stack until it empties.
*/
class MarkStack
{
friend class GCMarker;
uintptr_t *stack_;
uintptr_t *tos_;
uintptr_t *end_;
// The capacity we start with and reset() to.
size_t baseCapacity_;
size_t maxCapacity_;
public:
MarkStack(size_t maxCapacity)
: stack_(nullptr),
tos_(nullptr),
end_(nullptr),
baseCapacity_(0),
maxCapacity_(maxCapacity)
{}
~MarkStack() {
js_free(stack_);
}
size_t capacity() { return end_ - stack_; }
ptrdiff_t position() const { return tos_ - stack_; }
void setStack(uintptr_t *stack, size_t tosIndex, size_t capacity) {
stack_ = stack;
tos_ = stack + tosIndex;
end_ = stack + capacity;
}
bool init(JSGCMode gcMode);
void setBaseCapacity(JSGCMode mode);
size_t maxCapacity() const { return maxCapacity_; }
void setMaxCapacity(size_t maxCapacity);
bool push(uintptr_t item) {
if (tos_ == end_) {
if (!enlarge(1))
return false;
}
JS_ASSERT(tos_ < end_);
*tos_++ = item;
return true;
}
bool push(uintptr_t item1, uintptr_t item2, uintptr_t item3) {
uintptr_t *nextTos = tos_ + 3;
if (nextTos > end_) {
if (!enlarge(3))
return false;
nextTos = tos_ + 3;
}
JS_ASSERT(nextTos <= end_);
tos_[0] = item1;
tos_[1] = item2;
tos_[2] = item3;
tos_ = nextTos;
return true;
}
bool isEmpty() const {
return tos_ == stack_;
}
uintptr_t pop() {
JS_ASSERT(!isEmpty());
return *--tos_;
}
void reset();
/* Grow the stack, ensuring there is space for at least count elements. */
bool enlarge(unsigned count);
void setGCMode(JSGCMode gcMode);
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
};
class GCMarker : public JSTracer
{
public:
explicit GCMarker(JSRuntime *rt);
bool init(JSGCMode gcMode);
void setMaxCapacity(size_t maxCap) { stack.setMaxCapacity(maxCap); }
size_t maxCapacity() const { return stack.maxCapacity(); }
void start();
void stop();
void reset();
void pushObject(ObjectImpl *obj) {
pushTaggedPtr(ObjectTag, obj);
}
void pushType(types::TypeObject *type) {
pushTaggedPtr(TypeTag, type);
}
void pushJitCode(jit::JitCode *code) {
pushTaggedPtr(JitCodeTag, code);
}
uint32_t getMarkColor() const {
return color;
}
/*
* Care must be taken changing the mark color from gray to black. The cycle
* collector depends on the invariant that there are no black to gray edges
* in the GC heap. This invariant lets the CC not trace through black
* objects. If this invariant is violated, the cycle collector may free
* objects that are still reachable.
*/
void setMarkColorGray() {
JS_ASSERT(isDrained());
JS_ASSERT(color == gc::BLACK);
color = gc::GRAY;
}
void setMarkColorBlack() {
JS_ASSERT(isDrained());
JS_ASSERT(color == gc::GRAY);
color = gc::BLACK;
}
inline void delayMarkingArena(gc::ArenaHeader *aheader);
void delayMarkingChildren(const void *thing);
void markDelayedChildren(gc::ArenaHeader *aheader);
bool markDelayedChildren(SliceBudget &budget);
bool hasDelayedChildren() const {
return !!unmarkedArenaStackTop;
}
bool isDrained() {
return isMarkStackEmpty() && !unmarkedArenaStackTop;
}
bool drainMarkStack(SliceBudget &budget);
/*
* Gray marking must be done after all black marking is complete. However,
* we do not have write barriers on XPConnect roots. Therefore, XPConnect
* roots must be accumulated in the first slice of incremental GC. We
* accumulate these roots in the each compartment's gcGrayRoots vector and
* then mark them later, after black marking is complete for each
* compartment. This accumulation can fail, but in that case we switch to
* non-incremental GC.
*/
bool hasBufferedGrayRoots() const;
void startBufferingGrayRoots();
void endBufferingGrayRoots();
void resetBufferedGrayRoots();
void markBufferedGrayRoots(JS::Zone *zone);
static void GrayCallback(JSTracer *trc, void **thing, JSGCTraceKind kind);
void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
/* This is public exclusively for ScanRope. */
MarkStack stack;
private:
#ifdef DEBUG
void checkZone(void *p);
#else
void checkZone(void *p) {}
#endif
/*
* We use a common mark stack to mark GC things of different types and use
* the explicit tags to distinguish them when it cannot be deduced from
* the context of push or pop operation.
*/
enum StackTag {
ValueArrayTag,
ObjectTag,
TypeTag,
XmlTag,
SavedValueArrayTag,
JitCodeTag,
LastTag = JitCodeTag
};
static const uintptr_t StackTagMask = 7;
static_assert(StackTagMask >= uintptr_t(LastTag), "The tag mask must subsume the tags.");
static_assert(StackTagMask <= gc::CellMask, "The tag mask must be embeddable in a Cell*.");
void pushTaggedPtr(StackTag tag, void *ptr) {
checkZone(ptr);
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
JS_ASSERT(!(addr & StackTagMask));
if (!stack.push(addr | uintptr_t(tag)))
delayMarkingChildren(ptr);
}
void pushValueArray(JSObject *obj, void *start, void *end) {
checkZone(obj);
JS_ASSERT(start <= end);
uintptr_t tagged = reinterpret_cast<uintptr_t>(obj) | GCMarker::ValueArrayTag;
uintptr_t startAddr = reinterpret_cast<uintptr_t>(start);
uintptr_t endAddr = reinterpret_cast<uintptr_t>(end);
/*
* Push in the reverse order so obj will be on top. If we cannot push
* the array, we trigger delay marking for the whole object.
*/
if (!stack.push(endAddr, startAddr, tagged))
delayMarkingChildren(obj);
}
bool isMarkStackEmpty() {
return stack.isEmpty();
}
bool restoreValueArray(JSObject *obj, void **vpp, void **endp);
void saveValueRanges();
inline void processMarkStackTop(SliceBudget &budget);
void processMarkStackOther(uintptr_t tag, uintptr_t addr);
void appendGrayRoot(void *thing, JSGCTraceKind kind);
/* The color is only applied to objects and functions. */
uint32_t color;
/* Pointer to the top of the stack of arenas we are delaying marking on. */
js::gc::ArenaHeader *unmarkedArenaStackTop;
/* Count of arenas that are currently in the stack. */
mozilla::DebugOnly<size_t> markLaterArenas;
enum GrayBufferState {
GRAY_BUFFER_UNUSED,
GRAY_BUFFER_OK,
GRAY_BUFFER_FAILED
};
GrayBufferState grayBufferState;
/* Assert that start and stop are called with correct ordering. */
mozilla::DebugOnly<bool> started;
};
void
SetMarkStackLimit(JSRuntime *rt, size_t limit);
} /* namespace js */
/*
* Macro to test if a traversal is the marking phase of the GC.
*/
#define IS_GC_MARKING_TRACER(trc) \
((trc)->callback == nullptr || (trc)->callback == GCMarker::GrayCallback)
#endif /* js_Tracer_h */

View File

@ -6,6 +6,8 @@
#include "jit/AsmJSSignalHandlers.h"
#include "mozilla/BinarySearch.h"
#include "assembler/assembler/MacroAssembler.h"
#include "jit/AsmJSModule.h"
@ -207,35 +209,29 @@ SetXMMRegToNaN(bool isFloat32, T *xmm_reg)
}
}
struct GetHeapAccessOffset
{
const AsmJSModule &module;
explicit GetHeapAccessOffset(const AsmJSModule &module) : module(module) {}
uintptr_t operator[](size_t index) const {
return module.heapAccess(index).offset();
}
};
// Perform a binary search on the projected offsets of the known heap accesses
// in the module.
static const AsmJSHeapAccess *
LookupHeapAccess(const AsmJSModule &module, uint8_t *pc)
{
JS_ASSERT(module.containsPC(pc));
size_t targetOffset = pc - module.codeBase();
if (module.numHeapAccesses() == 0)
uintptr_t pcOff = pc - module.codeBase();
size_t match;
if (!BinarySearch(GetHeapAccessOffset(module), 0, module.numHeapAccesses(), pcOff, &match))
return nullptr;
size_t low = 0;
size_t high = module.numHeapAccesses() - 1;
while (high - low >= 2) {
size_t mid = low + (high - low) / 2;
uint32_t midOffset = module.heapAccess(mid).offset();
if (targetOffset == midOffset)
return &module.heapAccess(mid);
if (targetOffset < midOffset)
high = mid;
else
low = mid;
}
if (targetOffset == module.heapAccess(low).offset())
return &module.heapAccess(low);
if (targetOffset == module.heapAccess(high).offset())
return &module.heapAccess(high);
return nullptr;
return &module.heapAccess(match);
}
#endif

View File

@ -506,6 +506,7 @@ ValueNumberer::breakClass(MDefinition *def)
MDefinition *newRep = findSplit(def);
if (!newRep)
return;
markConsumers(def);
ValueNumberData *newdata = newRep->valueNumberData();
// Right now, |defdata| is at the front of the list, and |newdata| is
@ -544,8 +545,10 @@ ValueNumberer::breakClass(MDefinition *def)
// make the VN of every member in the class the VN of the new representative number.
for (MDefinition *tmp = newRep; tmp != nullptr; tmp = tmp->valueNumberData()->classNext) {
// if this instruction is already scheduled to be processed, don't do anything.
if (tmp->isInWorklist())
if (tmp->isInWorklist()) {
IonSpew(IonSpew_GVN, "Defer to a new congruence class: %d", tmp->id());
continue;
}
IonSpew(IonSpew_GVN, "Moving to a new congruence class: %d", tmp->id());
tmp->setValueNumber(newRep->id());
markConsumers(tmp);

View File

@ -2120,20 +2120,6 @@ typedef enum JSGCParamKey {
JSGC_DECOMMIT_THRESHOLD = 20
} JSGCParamKey;
typedef enum JSGCMode {
/* Perform only global GCs. */
JSGC_MODE_GLOBAL = 0,
/* Perform per-compartment GCs until too much garbage has accumulated. */
JSGC_MODE_COMPARTMENT = 1,
/*
* Collect in short time slices rather than all at once. Implies
* JSGC_MODE_COMPARTMENT.
*/
JSGC_MODE_INCREMENTAL = 2
} JSGCMode;
extern JS_PUBLIC_API(void)
JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value);

View File

@ -23,6 +23,7 @@
#include "jsutil.h"
#include "ds/Sort.h"
#include "gc/Heap.h"
#include "vm/ArgumentsObject.h"
#include "vm/ForkJoin.h"
#include "vm/Interpreter.h"

View File

@ -1338,6 +1338,26 @@ Allocator::Allocator(Zone *zone)
: zone_(zone)
{}
inline void
GCMarker::delayMarkingArena(ArenaHeader *aheader)
{
if (aheader->hasDelayedMarking) {
/* Arena already scheduled to be marked later */
return;
}
aheader->setNextDelayedMarking(unmarkedArenaStackTop);
unmarkedArenaStackTop = aheader;
markLaterArenas++;
}
void
GCMarker::delayMarkingChildren(const void *thing)
{
const Cell *cell = reinterpret_cast<const Cell *>(thing);
cell->arenaHeader()->markOverflow = 1;
delayMarkingArena(cell->arenaHeader());
}
inline void
ArenaLists::prepareForIncrementalGC(JSRuntime *rt)
{
@ -1849,284 +1869,6 @@ SliceBudget::checkOverBudget()
return over;
}
/*
* DoNotTraceWeakMaps: the GC is recomputing the liveness of WeakMap entries,
* so we delay visting entries.
*/
GCMarker::GCMarker(JSRuntime *rt)
: JSTracer(rt, nullptr, DoNotTraceWeakMaps),
stack(size_t(-1)),
color(BLACK),
started(false),
unmarkedArenaStackTop(nullptr),
markLaterArenas(0),
grayBufferState(GRAY_BUFFER_UNUSED)
{
}
bool
GCMarker::init(JSGCMode gcMode)
{
return stack.init(gcMode);
}
void
GCMarker::start()
{
JS_ASSERT(!started);
started = true;
color = BLACK;
JS_ASSERT(!unmarkedArenaStackTop);
JS_ASSERT(markLaterArenas == 0);
}
void
GCMarker::stop()
{
JS_ASSERT(isDrained());
JS_ASSERT(started);
started = false;
JS_ASSERT(!unmarkedArenaStackTop);
JS_ASSERT(markLaterArenas == 0);
/* Free non-ballast stack memory. */
stack.reset();
resetBufferedGrayRoots();
grayBufferState = GRAY_BUFFER_UNUSED;
}
void
GCMarker::reset()
{
color = BLACK;
stack.reset();
JS_ASSERT(isMarkStackEmpty());
while (unmarkedArenaStackTop) {
ArenaHeader *aheader = unmarkedArenaStackTop;
JS_ASSERT(aheader->hasDelayedMarking);
JS_ASSERT(markLaterArenas);
unmarkedArenaStackTop = aheader->getNextDelayedMarking();
aheader->unsetDelayedMarking();
aheader->markOverflow = 0;
aheader->allocatedDuringIncremental = 0;
markLaterArenas--;
}
JS_ASSERT(isDrained());
JS_ASSERT(!markLaterArenas);
}
/*
* When the native stack is low, the GC does not call JS_TraceChildren to mark
* the reachable "children" of the thing. Rather the thing is put aside and
* JS_TraceChildren is called later with more space on the C stack.
*
* To implement such delayed marking of the children with minimal overhead for
* the normal case of sufficient native stack, the code adds a field per
* arena. The field markingDelay->link links all arenas with delayed things
* into a stack list with the pointer to stack top in
* GCMarker::unmarkedArenaStackTop. delayMarkingChildren adds
* arenas to the stack as necessary while markDelayedChildren pops the arenas
* from the stack until it empties.
*/
inline void
GCMarker::delayMarkingArena(ArenaHeader *aheader)
{
if (aheader->hasDelayedMarking) {
/* Arena already scheduled to be marked later */
return;
}
aheader->setNextDelayedMarking(unmarkedArenaStackTop);
unmarkedArenaStackTop = aheader;
markLaterArenas++;
}
void
GCMarker::delayMarkingChildren(const void *thing)
{
const Cell *cell = reinterpret_cast<const Cell *>(thing);
cell->arenaHeader()->markOverflow = 1;
delayMarkingArena(cell->arenaHeader());
}
void
GCMarker::markDelayedChildren(ArenaHeader *aheader)
{
if (aheader->markOverflow) {
bool always = aheader->allocatedDuringIncremental;
aheader->markOverflow = 0;
for (CellIterUnderGC i(aheader); !i.done(); i.next()) {
Cell *t = i.getCell();
if (always || t->isMarked()) {
t->markIfUnmarked();
JS_TraceChildren(this, t, MapAllocToTraceKind(aheader->getAllocKind()));
}
}
} else {
JS_ASSERT(aheader->allocatedDuringIncremental);
PushArena(this, aheader);
}
aheader->allocatedDuringIncremental = 0;
/*
* Note that during an incremental GC we may still be allocating into
* aheader. However, prepareForIncrementalGC sets the
* allocatedDuringIncremental flag if we continue marking.
*/
}
bool
GCMarker::markDelayedChildren(SliceBudget &budget)
{
gcstats::MaybeAutoPhase ap;
if (runtime()->gcIncrementalState == MARK)
ap.construct(runtime()->gcStats, gcstats::PHASE_MARK_DELAYED);
JS_ASSERT(unmarkedArenaStackTop);
do {
/*
* If marking gets delayed at the same arena again, we must repeat
* marking of its things. For that we pop arena from the stack and
* clear its hasDelayedMarking flag before we begin the marking.
*/
ArenaHeader *aheader = unmarkedArenaStackTop;
JS_ASSERT(aheader->hasDelayedMarking);
JS_ASSERT(markLaterArenas);
unmarkedArenaStackTop = aheader->getNextDelayedMarking();
aheader->unsetDelayedMarking();
markLaterArenas--;
markDelayedChildren(aheader);
budget.step(150);
if (budget.isOverBudget())
return false;
} while (unmarkedArenaStackTop);
JS_ASSERT(!markLaterArenas);
return true;
}
#ifdef DEBUG
void
GCMarker::checkZone(void *p)
{
JS_ASSERT(started);
DebugOnly<Cell *> cell = static_cast<Cell *>(p);
JS_ASSERT_IF(cell->isTenured(), cell->tenuredZone()->isCollecting());
}
#endif
bool
GCMarker::hasBufferedGrayRoots() const
{
return grayBufferState == GRAY_BUFFER_OK;
}
void
GCMarker::startBufferingGrayRoots()
{
JS_ASSERT(grayBufferState == GRAY_BUFFER_UNUSED);
grayBufferState = GRAY_BUFFER_OK;
for (GCZonesIter zone(runtime()); !zone.done(); zone.next())
JS_ASSERT(zone->gcGrayRoots.empty());
JS_ASSERT(!callback);
callback = GrayCallback;
JS_ASSERT(IS_GC_MARKING_TRACER(this));
}
void
GCMarker::endBufferingGrayRoots()
{
JS_ASSERT(callback == GrayCallback);
callback = nullptr;
JS_ASSERT(IS_GC_MARKING_TRACER(this));
JS_ASSERT(grayBufferState == GRAY_BUFFER_OK ||
grayBufferState == GRAY_BUFFER_FAILED);
}
void
GCMarker::resetBufferedGrayRoots()
{
for (GCZonesIter zone(runtime()); !zone.done(); zone.next())
zone->gcGrayRoots.clearAndFree();
}
void
GCMarker::markBufferedGrayRoots(JS::Zone *zone)
{
JS_ASSERT(grayBufferState == GRAY_BUFFER_OK);
JS_ASSERT(zone->isGCMarkingGray());
for (GrayRoot *elem = zone->gcGrayRoots.begin(); elem != zone->gcGrayRoots.end(); elem++) {
#ifdef DEBUG
setTracingDetails(elem->debugPrinter, elem->debugPrintArg, elem->debugPrintIndex);
#endif
void *tmp = elem->thing;
setTracingLocation((void *)&elem->thing);
MarkKind(this, &tmp, elem->kind);
JS_ASSERT(tmp == elem->thing);
}
}
void
GCMarker::appendGrayRoot(void *thing, JSGCTraceKind kind)
{
JS_ASSERT(started);
if (grayBufferState == GRAY_BUFFER_FAILED)
return;
GrayRoot root(thing, kind);
#ifdef DEBUG
root.debugPrinter = debugPrinter();
root.debugPrintArg = debugPrintArg();
root.debugPrintIndex = debugPrintIndex();
#endif
Zone *zone = static_cast<Cell *>(thing)->tenuredZone();
if (zone->isCollecting()) {
zone->maybeAlive = true;
if (!zone->gcGrayRoots.append(root)) {
resetBufferedGrayRoots();
grayBufferState = GRAY_BUFFER_FAILED;
}
}
}
void
GCMarker::GrayCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind)
{
JS_ASSERT(thingp);
JS_ASSERT(*thingp);
GCMarker *gcmarker = static_cast<GCMarker *>(trc);
gcmarker->appendGrayRoot(*thingp, kind);
}
size_t
GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
size_t size = stack.sizeOfExcludingThis(mallocSizeOf);
for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next())
size += zone->gcGrayRoots.sizeOfExcludingThis(mallocSizeOf);
return size;
}
void
js::SetMarkStackLimit(JSRuntime *rt, size_t limit)
{
JS_ASSERT(!rt->isHeapBusy());
AutoStopVerifyingBarriers pauseVerification(rt, false);
rt->gcMarker.setMaxCapacity(limit);
}
void
js::MarkCompartmentActive(InterpreterFrame *fp)
{

View File

@ -15,7 +15,6 @@
#include "jslock.h"
#include "jsobj.h"
#include "gc/Tracer.h"
#include "js/GCAPI.h"
#include "js/SliceBudget.h"
#include "js/Vector.h"
@ -930,157 +929,6 @@ struct GCChunkHasher {
typedef HashSet<js::gc::Chunk *, GCChunkHasher, SystemAllocPolicy> GCChunkSet;
static const size_t NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY = 4096;
static const size_t INCREMENTAL_MARK_STACK_BASE_CAPACITY = 32768;
template<class T>
struct MarkStack {
T *stack_;
T *tos_;
T *end_;
// The capacity we start with and reset() to.
size_t baseCapacity_;
size_t maxCapacity_;
MarkStack(size_t maxCapacity)
: stack_(nullptr),
tos_(nullptr),
end_(nullptr),
baseCapacity_(0),
maxCapacity_(maxCapacity)
{}
~MarkStack() {
js_free(stack_);
}
size_t capacity() { return end_ - stack_; }
ptrdiff_t position() const { return tos_ - stack_; }
void setStack(T *stack, size_t tosIndex, size_t capacity) {
stack_ = stack;
tos_ = stack + tosIndex;
end_ = stack + capacity;
}
void setBaseCapacity(JSGCMode mode) {
switch (mode) {
case JSGC_MODE_GLOBAL:
case JSGC_MODE_COMPARTMENT:
baseCapacity_ = NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY;
break;
case JSGC_MODE_INCREMENTAL:
baseCapacity_ = INCREMENTAL_MARK_STACK_BASE_CAPACITY;
break;
default:
MOZ_ASSUME_UNREACHABLE("bad gc mode");
}
if (baseCapacity_ > maxCapacity_)
baseCapacity_ = maxCapacity_;
}
bool init(JSGCMode gcMode) {
setBaseCapacity(gcMode);
JS_ASSERT(!stack_);
T *newStack = js_pod_malloc<T>(baseCapacity_);
if (!newStack)
return false;
setStack(newStack, 0, baseCapacity_);
return true;
}
void setMaxCapacity(size_t maxCapacity) {
JS_ASSERT(isEmpty());
maxCapacity_ = maxCapacity;
if (baseCapacity_ > maxCapacity_)
baseCapacity_ = maxCapacity_;
reset();
}
bool push(T item) {
if (tos_ == end_) {
if (!enlarge(1))
return false;
}
JS_ASSERT(tos_ < end_);
*tos_++ = item;
return true;
}
bool push(T item1, T item2, T item3) {
T *nextTos = tos_ + 3;
if (nextTos > end_) {
if (!enlarge(3))
return false;
nextTos = tos_ + 3;
}
JS_ASSERT(nextTos <= end_);
tos_[0] = item1;
tos_[1] = item2;
tos_[2] = item3;
tos_ = nextTos;
return true;
}
bool isEmpty() const {
return tos_ == stack_;
}
T pop() {
JS_ASSERT(!isEmpty());
return *--tos_;
}
void reset() {
if (capacity() == baseCapacity_) {
// No size change; keep the current stack.
setStack(stack_, 0, baseCapacity_);
return;
}
T *newStack = (T *)js_realloc(stack_, sizeof(T) * baseCapacity_);
if (!newStack) {
// If the realloc fails, just keep using the existing stack; it's
// not ideal but better than failing.
newStack = stack_;
baseCapacity_ = capacity();
}
setStack(newStack, 0, baseCapacity_);
}
/* Grow the stack, ensuring there is space for at least count elements. */
bool enlarge(unsigned count) {
size_t newCapacity = Min(maxCapacity_, capacity() * 2);
if (newCapacity < capacity() + count)
return false;
size_t tosIndex = position();
T *newStack = (T *)js_realloc(stack_, sizeof(T) * newCapacity);
if (!newStack)
return false;
setStack(newStack, tosIndex, newCapacity);
return true;
}
void setGCMode(JSGCMode gcMode) {
// The mark stack won't be resized until the next call to reset(), but
// that will happen at the end of the next GC.
setBaseCapacity(gcMode);
}
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
return mallocSizeOf(stack_);
}
};
struct GrayRoot {
void *thing;
JSGCTraceKind kind;
@ -1094,178 +942,6 @@ struct GrayRoot {
: thing(thing), kind(kind) {}
};
struct GCMarker : public JSTracer {
private:
/*
* We use a common mark stack to mark GC things of different types and use
* the explicit tags to distinguish them when it cannot be deduced from
* the context of push or pop operation.
*/
enum StackTag {
ValueArrayTag,
ObjectTag,
TypeTag,
XmlTag,
SavedValueArrayTag,
JitCodeTag,
LastTag = JitCodeTag
};
static const uintptr_t StackTagMask = 7;
static void staticAsserts() {
JS_STATIC_ASSERT(StackTagMask >= uintptr_t(LastTag));
JS_STATIC_ASSERT(StackTagMask <= gc::CellMask);
}
public:
explicit GCMarker(JSRuntime *rt);
bool init(JSGCMode gcMode);
void setMaxCapacity(size_t maxCap) { stack.setMaxCapacity(maxCap); }
size_t maxCapacity() const { return stack.maxCapacity_; }
void start();
void stop();
void reset();
void pushObject(ObjectImpl *obj) {
pushTaggedPtr(ObjectTag, obj);
}
void pushType(types::TypeObject *type) {
pushTaggedPtr(TypeTag, type);
}
void pushJitCode(jit::JitCode *code) {
pushTaggedPtr(JitCodeTag, code);
}
uint32_t getMarkColor() const {
return color;
}
/*
* Care must be taken changing the mark color from gray to black. The cycle
* collector depends on the invariant that there are no black to gray edges
* in the GC heap. This invariant lets the CC not trace through black
* objects. If this invariant is violated, the cycle collector may free
* objects that are still reachable.
*/
void setMarkColorGray() {
JS_ASSERT(isDrained());
JS_ASSERT(color == gc::BLACK);
color = gc::GRAY;
}
void setMarkColorBlack() {
JS_ASSERT(isDrained());
JS_ASSERT(color == gc::GRAY);
color = gc::BLACK;
}
inline void delayMarkingArena(gc::ArenaHeader *aheader);
void delayMarkingChildren(const void *thing);
void markDelayedChildren(gc::ArenaHeader *aheader);
bool markDelayedChildren(SliceBudget &budget);
bool hasDelayedChildren() const {
return !!unmarkedArenaStackTop;
}
bool isDrained() {
return isMarkStackEmpty() && !unmarkedArenaStackTop;
}
bool drainMarkStack(SliceBudget &budget);
/*
* Gray marking must be done after all black marking is complete. However,
* we do not have write barriers on XPConnect roots. Therefore, XPConnect
* roots must be accumulated in the first slice of incremental GC. We
* accumulate these roots in the each compartment's gcGrayRoots vector and
* then mark them later, after black marking is complete for each
* compartment. This accumulation can fail, but in that case we switch to
* non-incremental GC.
*/
bool hasBufferedGrayRoots() const;
void startBufferingGrayRoots();
void endBufferingGrayRoots();
void resetBufferedGrayRoots();
void markBufferedGrayRoots(JS::Zone *zone);
static void GrayCallback(JSTracer *trc, void **thing, JSGCTraceKind kind);
void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
MarkStack<uintptr_t> stack;
private:
#ifdef DEBUG
void checkZone(void *p);
#else
void checkZone(void *p) {}
#endif
void pushTaggedPtr(StackTag tag, void *ptr) {
checkZone(ptr);
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
JS_ASSERT(!(addr & StackTagMask));
if (!stack.push(addr | uintptr_t(tag)))
delayMarkingChildren(ptr);
}
void pushValueArray(JSObject *obj, void *start, void *end) {
checkZone(obj);
JS_ASSERT(start <= end);
uintptr_t tagged = reinterpret_cast<uintptr_t>(obj) | GCMarker::ValueArrayTag;
uintptr_t startAddr = reinterpret_cast<uintptr_t>(start);
uintptr_t endAddr = reinterpret_cast<uintptr_t>(end);
/*
* Push in the reverse order so obj will be on top. If we cannot push
* the array, we trigger delay marking for the whole object.
*/
if (!stack.push(endAddr, startAddr, tagged))
delayMarkingChildren(obj);
}
bool isMarkStackEmpty() {
return stack.isEmpty();
}
bool restoreValueArray(JSObject *obj, void **vpp, void **endp);
void saveValueRanges();
inline void processMarkStackTop(SliceBudget &budget);
void processMarkStackOther(uintptr_t tag, uintptr_t addr);
void appendGrayRoot(void *thing, JSGCTraceKind kind);
/* The color is only applied to objects and functions. */
uint32_t color;
mozilla::DebugOnly<bool> started;
/* Pointer to the top of the stack of arenas we are delaying marking on. */
js::gc::ArenaHeader *unmarkedArenaStackTop;
/* Count of arenas that are currently in the stack. */
mozilla::DebugOnly<size_t> markLaterArenas;
enum GrayBufferState
{
GRAY_BUFFER_UNUSED,
GRAY_BUFFER_OK,
GRAY_BUFFER_FAILED
};
GrayBufferState grayBufferState;
};
void
SetMarkStackLimit(JSRuntime *rt, size_t limit);
void
MarkStackRangeConservatively(JSTracer *trc, Value *begin, Value *end);
@ -1320,12 +996,6 @@ IterateScripts(JSRuntime *rt, JSCompartment *compartment,
extern void
js_FinalizeStringRT(JSRuntime *rt, JSString *str);
/*
* Macro to test if a traversal is the marking phase of the GC.
*/
#define IS_GC_MARKING_TRACER(trc) \
((trc)->callback == nullptr || (trc)->callback == GCMarker::GrayCallback)
namespace js {
JSCompartment *

View File

@ -18,6 +18,7 @@
#include "mozilla/MemoryReporting.h"
#include "gc/Barrier.h"
#include "gc/Marking.h"
#include "js/GCAPI.h"
#include "vm/ObjectImpl.h"

View File

@ -34,6 +34,7 @@
#ifdef JSGC_GENERATIONAL
# include "gc/StoreBuffer.h"
#endif
#include "gc/Tracer.h"
#ifdef XP_MACOSX
# include "jit/AsmJSSignalHandlers.h"
#endif

30
media/libopus/Makefile.in Normal file
View File

@ -0,0 +1,30 @@
# 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/.
ifdef GNU_AS
ifeq ($(CPU_ARCH),arm)
# These flags are a lie; they're just used to enable the requisite
# opcodes; actual arch detection is done at runtime.
ASFLAGS = -march=armv7-a -mfpu=neon
celt_pitch_xcorr_arm-gnu.$(ASM_SUFFIX): celt_arm_dir celt/arm/armopts-gnu.S
# we need to throw this here because upstream has this path hardcoded
celt_arm_dir:
mkdir -p celt/arm
# armopts needs a specific rule, because arm2gnu.pl will always add the .S
# suffix when translating the files that include it.
celt/arm/armopts-gnu.S: celt/arm/armopts.s
$(PERL) $(srcdir)/celt/arm/arm2gnu.pl < $< > $@
# For all others, we can use an implicit rule with the configured $(ASM_SUFFIX).
%-gnu.$(ASM_SUFFIX): celt/arm/%.s
$(PERL) $(srcdir)/celt/arm/arm2gnu.pl < $< > $@
endif
endif
include $(topsrcdir)/config/rules.mk

316
media/libopus/celt/arm/arm2gnu.pl Executable file
View File

@ -0,0 +1,316 @@
#!/usr/bin/perl
my $bigend; # little/big endian
my $nxstack;
$nxstack = 0;
eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
if $running_under_some_shell;
while ($ARGV[0] =~ /^-/) {
$_ = shift;
last if /^--/;
if (/^-n/) {
$nflag++;
next;
}
die "I don't recognize this switch: $_\\n";
}
$printit++ unless $nflag;
$\ = "\n"; # automatically add newline on print
$n=0;
$thumb = 0; # ARM mode by default, not Thumb.
@proc_stack = ();
LINE:
while (<>) {
# For ADRLs we need to add a new line after the substituted one.
$addPadding = 0;
# First, we do not dare to touch *anything* inside double quotes, do we?
# Second, if you want a dollar character in the string,
# insert two of them -- that's how ARM C and assembler treat strings.
s/^([A-Za-z_]\w*)[ \t]+DCB[ \t]*\"/$1: .ascii \"/ && do { s/\$\$/\$/g; next };
s/\bDCB\b[ \t]*\"/.ascii \"/ && do { s/\$\$/\$/g; next };
s/^(\S+)\s+RN\s+(\S+)/$1 .req r$2/ && do { s/\$\$/\$/g; next };
# If there's nothing on a line but a comment, don't try to apply any further
# substitutions (this is a cheap hack to avoid mucking up the license header)
s/^([ \t]*);/$1@/ && do { s/\$\$/\$/g; next };
# If substituted -- leave immediately !
s/@/,:/;
s/;/@/;
while ( /@.*'/ ) {
s/(@.*)'/$1/g;
}
s/\{FALSE\}/0/g;
s/\{TRUE\}/1/g;
s/\{(\w\w\w\w+)\}/$1/g;
s/\bINCLUDE[ \t]*([^ \t\n]+)/.include \"$1\"/;
s/\bGET[ \t]*([^ \t\n]+)/.include \"${ my $x=$1; $x =~ s|\.s|-gnu.S|; \$x }\"/;
s/\bIMPORT\b/.extern/;
s/\bEXPORT\b/.global/;
s/^(\s+)\[/$1IF/;
s/^(\s+)\|/$1ELSE/;
s/^(\s+)\]/$1ENDIF/;
s/IF *:DEF:/ .ifdef/;
s/IF *:LNOT: *:DEF:/ .ifndef/;
s/ELSE/ .else/;
s/ENDIF/ .endif/;
if( /\bIF\b/ ) {
s/\bIF\b/ .if/;
s/=/==/;
}
if ( $n == 2) {
s/\$/\\/g;
}
if ($n == 1) {
s/\$//g;
s/label//g;
$n = 2;
}
if ( /MACRO/ ) {
s/MACRO *\n/.macro/;
$n=1;
}
if ( /\bMEND\b/ ) {
s/\bMEND\b/.endm/;
$n=0;
}
# ".rdata" doesn't work in 'as' version 2.13.2, as it is ".rodata" there.
#
if ( /\bAREA\b/ ) {
my $align;
$align = "2";
if ( /ALIGN=(\d+)/ ) {
$align = $1;
}
if ( /CODE/ ) {
$nxstack = 1;
}
s/^(.+)CODE(.+)READONLY(.*)/ .text/;
s/^(.+)DATA(.+)READONLY(.*)/ .section .rdata/;
s/^(.+)\|\|\.data\|\|(.+)/ .data/;
s/^(.+)\|\|\.bss\|\|(.+)/ .bss/;
s/$/; .p2align $align/;
# Enable NEON instructions but don't produce a binary that requires
# ARMv7. RVCT does not have equivalent directives, so we just do this
# for all CODE areas.
if ( /.text/ ) {
# Separating .arch, .fpu, etc., by semicolons does not work (gas
# thinks the semicolon is part of the arch name, even when there's
# whitespace separating them). Sadly this means our line numbers
# won't match the original source file (we could use the .line
# directive, which is documented to be obsolete, but then gdb will
# show the wrong line in the translated source file).
s/$/; .arch armv7-a\n .fpu neon\n .object_arch armv4t/;
}
}
s/\|\|\.constdata\$(\d+)\|\|/.L_CONST$1/; # ||.constdata$3||
s/\|\|\.bss\$(\d+)\|\|/.L_BSS$1/; # ||.bss$2||
s/\|\|\.data\$(\d+)\|\|/.L_DATA$1/; # ||.data$2||
s/\|\|([a-zA-Z0-9_]+)\@([a-zA-Z0-9_]+)\|\|/@ $&/;
s/^(\s+)\%(\s)/ .space $1/;
s/\|(.+)\.(\d+)\|/\.$1_$2/; # |L80.123| -> .L80_123
s/\bCODE32\b/.code 32/ && do {$thumb = 0};
s/\bCODE16\b/.code 16/ && do {$thumb = 1};
if (/\bPROC\b/)
{
my $prefix;
my $proc;
/^([A-Za-z_\.]\w+)\b/;
$proc = $1;
$prefix = "";
if ($proc)
{
$prefix = $prefix.sprintf("\t.type\t%s, %%function; ",$proc);
push(@proc_stack, $proc);
s/^[A-Za-z_\.]\w+/$&:/;
}
$prefix = $prefix."\t.thumb_func; " if ($thumb);
s/\bPROC\b/@ $&/;
$_ = $prefix.$_;
}
s/^(\s*)(S|Q|SH|U|UQ|UH)ASX\b/$1$2ADDSUBX/;
s/^(\s*)(S|Q|SH|U|UQ|UH)SAX\b/$1$2SUBADDX/;
if (/\bENDP\b/)
{
my $proc;
s/\bENDP\b/@ $&/;
$proc = pop(@proc_stack);
$_ = "\t.size $proc, .-$proc".$_ if ($proc);
}
s/\bSUBT\b/@ $&/;
s/\bDATA\b/@ $&/; # DATA directive is deprecated -- Asm guide, p.7-25
s/\bKEEP\b/@ $&/;
s/\bEXPORTAS\b/@ $&/;
s/\|\|(.)+\bEQU\b/@ $&/;
s/\|\|([\w\$]+)\|\|/$1/;
s/\bENTRY\b/@ $&/;
s/\bASSERT\b/@ $&/;
s/\bGBLL\b/@ $&/;
s/\bGBLA\b/@ $&/;
s/^\W+OPT\b/@ $&/;
s/:OR:/|/g;
s/:SHL:/<</g;
s/:SHR:/>>/g;
s/:AND:/&/g;
s/:LAND:/&&/g;
s/CPSR/cpsr/;
s/SPSR/spsr/;
s/ALIGN$/.balign 4/;
s/ALIGN\s+([0-9x]+)$/.balign $1/;
s/psr_cxsf/psr_all/;
s/LTORG/.ltorg/;
s/^([A-Za-z_]\w*)[ \t]+EQU/ .set $1,/;
s/^([A-Za-z_]\w*)[ \t]+SETL/ .set $1,/;
s/^([A-Za-z_]\w*)[ \t]+SETA/ .set $1,/;
s/^([A-Za-z_]\w*)[ \t]+\*/ .set $1,/;
# {PC} + 0xdeadfeed --> . + 0xdeadfeed
s/\{PC\} \+/ \. +/;
# Single hex constant on the line !
#
# >>> NOTE <<<
# Double-precision floats in gcc are always mixed-endian, which means
# bytes in two words are little-endian, but words are big-endian.
# So, 0x0000deadfeed0000 would be stored as 0x0000dead at low address
# and 0xfeed0000 at high address.
#
s/\bDCFD\b[ \t]+0x([a-fA-F0-9]{8})([a-fA-F0-9]{8})/.long 0x$1, 0x$2/;
# Only decimal constants on the line, no hex !
s/\bDCFD\b[ \t]+([0-9\.\-]+)/.double $1/;
# Single hex constant on the line !
# s/\bDCFS\b[ \t]+0x([a-f0-9]{8})([a-f0-9]{8})/.long 0x$1, 0x$2/;
# Only decimal constants on the line, no hex !
# s/\bDCFS\b[ \t]+([0-9\.\-]+)/.double $1/;
s/\bDCFS[ \t]+0x/.word 0x/;
s/\bDCFS\b/.float/;
s/^([A-Za-z_]\w*)[ \t]+DCD/$1 .word/;
s/\bDCD\b/.word/;
s/^([A-Za-z_]\w*)[ \t]+DCW/$1 .short/;
s/\bDCW\b/.short/;
s/^([A-Za-z_]\w*)[ \t]+DCB/$1 .byte/;
s/\bDCB\b/.byte/;
s/^([A-Za-z_]\w*)[ \t]+\%/.comm $1,/;
s/^[A-Za-z_\.]\w+/$&:/;
s/^(\d+)/$1:/;
s/\%(\d+)/$1b_or_f/;
s/\%[Bb](\d+)/$1b/;
s/\%[Ff](\d+)/$1f/;
s/\%[Ff][Tt](\d+)/$1f/;
s/&([\dA-Fa-f]+)/0x$1/;
if ( /\b2_[01]+\b/ ) {
s/\b2_([01]+)\b/conv$1&&&&/g;
while ( /[01][01][01][01]&&&&/ ) {
s/0000&&&&/&&&&0/g;
s/0001&&&&/&&&&1/g;
s/0010&&&&/&&&&2/g;
s/0011&&&&/&&&&3/g;
s/0100&&&&/&&&&4/g;
s/0101&&&&/&&&&5/g;
s/0110&&&&/&&&&6/g;
s/0111&&&&/&&&&7/g;
s/1000&&&&/&&&&8/g;
s/1001&&&&/&&&&9/g;
s/1010&&&&/&&&&A/g;
s/1011&&&&/&&&&B/g;
s/1100&&&&/&&&&C/g;
s/1101&&&&/&&&&D/g;
s/1110&&&&/&&&&E/g;
s/1111&&&&/&&&&F/g;
}
s/000&&&&/&&&&0/g;
s/001&&&&/&&&&1/g;
s/010&&&&/&&&&2/g;
s/011&&&&/&&&&3/g;
s/100&&&&/&&&&4/g;
s/101&&&&/&&&&5/g;
s/110&&&&/&&&&6/g;
s/111&&&&/&&&&7/g;
s/00&&&&/&&&&0/g;
s/01&&&&/&&&&1/g;
s/10&&&&/&&&&2/g;
s/11&&&&/&&&&3/g;
s/0&&&&/&&&&0/g;
s/1&&&&/&&&&1/g;
s/conv&&&&/0x/g;
}
if ( /commandline/)
{
if( /-bigend/)
{
$bigend=1;
}
}
if ( /\bDCDU\b/ )
{
my $cmd=$_;
my $value;
my $prefix;
my $w1;
my $w2;
my $w3;
my $w4;
s/\s+DCDU\b/@ $&/;
$cmd =~ /\bDCDU\b\s+0x(\d+)/;
$value = $1;
$value =~ /(\w\w)(\w\w)(\w\w)(\w\w)/;
$w1 = $1;
$w2 = $2;
$w3 = $3;
$w4 = $4;
if( $bigend ne "")
{
# big endian
$prefix = "\t.byte\t0x".$w1.";".
"\t.byte\t0x".$w2.";".
"\t.byte\t0x".$w3.";".
"\t.byte\t0x".$w4."; ";
}
else
{
# little endian
$prefix = "\t.byte\t0x".$w4.";".
"\t.byte\t0x".$w3.";".
"\t.byte\t0x".$w2.";".
"\t.byte\t0x".$w1."; ";
}
$_=$prefix.$_;
}
if ( /\badrl\b/i )
{
s/\badrl\s+(\w+)\s*,\s*(\w+)/ldr $1,=$2/i;
$addPadding = 1;
}
s/\bEND\b/@ END/;
} continue {
printf ("%s", $_) if $printit;
if ($addPadding != 0)
{
printf (" mov r0,r0\n");
$addPadding = 0;
}
}
#If we had a code section, mark that this object doesn't need an executable
# stack.
if ($nxstack) {
printf (" .section\t.note.GNU-stack,\"\",\%\%progbits\n");
}

View File

@ -0,0 +1,37 @@
/* Copyright (C) 2013 Mozilla Corporation */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
; Set the following to 1 if we have EDSP instructions
; (LDRD/STRD, etc., ARMv5E and later).
OPUS_ARM_MAY_HAVE_EDSP * 1
; Set the following to 1 if we have ARMv6 media instructions.
OPUS_ARM_MAY_HAVE_MEDIA * 1
; Set the following to 1 if we have NEON (some ARMv7)
OPUS_ARM_MAY_HAVE_NEON * 1
END

View File

@ -19,6 +19,15 @@ DEFINES['OPUS_BUILD'] = True
DEFINES['OPUS_VERSION'] = '"v1.1-mozilla"'
DEFINES['USE_ALLOCA'] = True
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_AS']:
DEFINES['OPUS_ARM_ASM'] = True
DEFINES['OPUS_ARM_EXTERNAL_ASM'] = True
DEFINES['OPUS_ARM_INLINE_ASM'] = True
DEFINES['OPUS_ARM_INLINE_EDSP'] = True
DEFINES['OPUS_ARM_MAY_HAVE_EDSP'] = True
DEFINES['OPUS_ARM_MAY_HAVE_MEDIA'] = True
DEFINES['OPUS_ARM_MAY_HAVE_NEON'] = True
if CONFIG['MOZ_DEBUG']:
DEFINES['ENABLE_ASSERTIONS'] = True
@ -68,6 +77,20 @@ else:
]
SOURCES += silk_sources_fixed
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_AS']:
SOURCES += celt_sources_arm
GENERATED_SOURCES += [ '%s.%s' % (f, CONFIG['ASM_SUFFIX']) for f in [
'celt_pitch_xcorr_arm-gnu',
]]
# -Os is significantly slower, enable -O3 unless optimization is disabled
if CONFIG['MOZ_OPTIMIZE']:
CFLAGS += [
'-O3',
]
CXXFLAGS += [
'-O3',
]
# Suppress warnings in third-party code.
if CONFIG['GNU_CC']:
CFLAGS += ['-Wno-declaration-after-statement']

8
media/libopus/update.sh Normal file → Executable file
View File

@ -11,7 +11,7 @@
TARGET='.'
STATIC_FILES="COPYING"
STATIC_FILES="COPYING celt/arm/arm2gnu.pl"
MK_FILES="opus_sources.mk celt_sources.mk silk_sources.mk \
opus_headers.mk celt_headers.mk silk_headers.mk"
@ -49,6 +49,12 @@ for file in ${STATIC_FILES} ${SRC_FILES} ${HDR_FILES}; do
${cmd}
done
sed \
-e s/@OPUS_ARM_MAY_HAVE_EDSP@/1/g \
-e s/@OPUS_ARM_MAY_HAVE_MEDIA@/1/g \
-e s/@OPUS_ARM_MAY_HAVE_NEON@/1/g \
$1/celt/arm/armopts.s.in > ${TARGET}/celt/arm/armopts.s
# query git for the revision we're copying from
if test -d $1/.git; then
version=$(cd $1 && git describe --tags --match 'v*' --dirty)

66
mfbt/BinarySearch.h Normal file
View File

@ -0,0 +1,66 @@
/* -*- 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/. */
#ifndef mozilla_BinarySearch_h
#define mozilla_BinarySearch_h
#include "mozilla/Assertions.h"
#include <stddef.h>
namespace mozilla {
/*
* The algorithm searches the given container 'c' over the sorted index range
* [begin, end) for an index 'i' where 'c[i] == target'. If such an index 'i' is
* found, BinarySearch returns 'true' and the index is returned via the outparam
* 'matchOrInsertionPoint'. If no index is found, BinarySearch returns 'false'
* and the outparam returns the first index in [begin, end] where 'target' can
* be inserted to maintain sorted order.
*
* Example:
*
* Vector<int> sortedInts = ...
*
* size_t match;
* if (BinarySearch(sortedInts, 0, sortedInts.length(), 13, &match))
* printf("found 13 at %lu\n", match);
*/
template <typename Container, typename T>
bool
BinarySearch(const Container &c, size_t begin, size_t end, T target, size_t *matchOrInsertionPoint)
{
MOZ_ASSERT(begin <= end);
size_t low = begin;
size_t high = end;
while (low != high) {
size_t middle = low + (high - low) / 2;
const T &middleValue = c[middle];
MOZ_ASSERT(c[low] <= c[middle]);
MOZ_ASSERT(c[middle] <= c[high - 1]);
MOZ_ASSERT(c[low] <= c[high - 1]);
if (target == middleValue) {
*matchOrInsertionPoint = middle;
return true;
}
if (target < middleValue)
high = middle;
else
low = middle + 1;
}
*matchOrInsertionPoint = low;
return false;
}
} // namespace mozilla
#endif // mozilla_BinarySearch_h

View File

@ -16,6 +16,7 @@ EXPORTS.mozilla = [
'Assertions.h',
'Atomics.h',
'Attributes.h',
'BinarySearch.h',
'BloomFilter.h',
'Casting.h',
'ChaosMode.h',

View File

@ -0,0 +1,75 @@
/* -*- 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 "mozilla/Assertions.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/Vector.h"
using mozilla::Vector;
using mozilla::BinarySearch;
struct Person
{
int age;
int id;
Person(int age, int id) : age(age), id(id) {}
};
struct GetAge
{
Vector<Person> &v;
GetAge(Vector<Person> &v) : v(v) {}
int operator[](size_t index) const { return v[index].age; }
};
int main()
{
size_t m;
Vector<int> v1;
v1.append(2);
v1.append(4);
v1.append(6);
v1.append(8);
MOZ_ASSERT(!BinarySearch(v1, 0, v1.length(), 1, &m) && m == 0);
MOZ_ASSERT( BinarySearch(v1, 0, v1.length(), 2, &m) && m == 0);
MOZ_ASSERT(!BinarySearch(v1, 0, v1.length(), 3, &m) && m == 1);
MOZ_ASSERT( BinarySearch(v1, 0, v1.length(), 4, &m) && m == 1);
MOZ_ASSERT(!BinarySearch(v1, 0, v1.length(), 5, &m) && m == 2);
MOZ_ASSERT( BinarySearch(v1, 0, v1.length(), 6, &m) && m == 2);
MOZ_ASSERT(!BinarySearch(v1, 0, v1.length(), 7, &m) && m == 3);
MOZ_ASSERT( BinarySearch(v1, 0, v1.length(), 8, &m) && m == 3);
MOZ_ASSERT(!BinarySearch(v1, 0, v1.length(), 9, &m) && m == 4);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 1, &m) && m == 1);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 2, &m) && m == 1);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 3, &m) && m == 1);
MOZ_ASSERT( BinarySearch(v1, 1, 3, 4, &m) && m == 1);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 5, &m) && m == 2);
MOZ_ASSERT( BinarySearch(v1, 1, 3, 6, &m) && m == 2);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 7, &m) && m == 3);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 8, &m) && m == 3);
MOZ_ASSERT(!BinarySearch(v1, 1, 3, 9, &m) && m == 3);
MOZ_ASSERT(!BinarySearch(v1, 0, 0, 0, &m) && m == 0);
MOZ_ASSERT(!BinarySearch(v1, 0, 0, 9, &m) && m == 0);
Vector<int> v2;
MOZ_ASSERT(!BinarySearch(v2, 0, 0, 0, &m) && m == 0);
MOZ_ASSERT(!BinarySearch(v2, 0, 0, 9, &m) && m == 0);
Vector<Person> v3;
v3.append(Person(2, 42));
v3.append(Person(4, 13));
v3.append(Person(6, 360));
MOZ_ASSERT(!BinarySearch(GetAge(v3), 0, v3.length(), 1, &m) && m == 0);
MOZ_ASSERT( BinarySearch(GetAge(v3), 0, v3.length(), 2, &m) && m == 0);
MOZ_ASSERT(!BinarySearch(GetAge(v3), 0, v3.length(), 3, &m) && m == 1);
MOZ_ASSERT( BinarySearch(GetAge(v3), 0, v3.length(), 4, &m) && m == 1);
MOZ_ASSERT(!BinarySearch(GetAge(v3), 0, v3.length(), 5, &m) && m == 2);
MOZ_ASSERT( BinarySearch(GetAge(v3), 0, v3.length(), 6, &m) && m == 2);
MOZ_ASSERT(!BinarySearch(GetAge(v3), 0, v3.length(), 7, &m) && m == 3);
}

View File

@ -6,6 +6,7 @@
CPP_UNIT_TESTS += [
'TestAtomics.cpp',
'TestBinarySearch.cpp',
'TestBloomFilter.cpp',
'TestCasting.cpp',
'TestCeilingFloor.cpp',

View File

@ -109,11 +109,13 @@ class PinSiteDialog extends DialogFragment {
// If the user manually entered a search term or URL, wrap the value in
// a special URI until we can get a valid URL for this bookmark.
final String text = mSearch.getText().toString();
final String url = TopSitesPanel.encodeUserEnteredUrl(text);
mOnSiteSelectedListener.onSiteSelected(url, text);
final String text = mSearch.getText().toString().trim();
if (!TextUtils.isEmpty(text)) {
final String url = TopSitesPanel.encodeUserEnteredUrl(text);
mOnSiteSelectedListener.onSiteSelected(url, text);
dismiss();
}
dismiss();
return true;
}
});

View File

@ -107,6 +107,13 @@ public class TopSitesGridItemView extends RelativeLayout {
return mIsPinned;
}
/**
* @return true, if this view has no content to show.
*/
public boolean isEmpty() {
return mIsEmpty;
}
/**
* @param title The title for this view.
*/

View File

@ -125,7 +125,8 @@ public class TopSitesGridView extends GridView {
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Cursor cursor = (Cursor) parent.getItemAtPosition(position);
if (cursor == null) {
TopSitesGridItemView gridView = (TopSitesGridItemView) view;
if (cursor == null || gridView.isEmpty()) {
mContextMenuInfo = null;
return false;
}

View File

@ -92,6 +92,7 @@ nsFtpState::nsFtpState()
, mPort(21)
, mAddressChecked(false)
, mServerIsIPv6(false)
, mUseUTF8(false)
, mControlStatus(NS_OK)
, mDeferredCallbackPending(false)
{
@ -276,7 +277,12 @@ nsFtpState::EstablishControlConnection()
mServerType = mControlConnection->mServerType;
mPassword = mControlConnection->mPassword;
mPwd = mControlConnection->mPwd;
mUseUTF8 = mControlConnection->mUseUTF8;
mTryingCachedControl = true;
// we have to set charset to connection if server supports utf-8
if (mUseUTF8)
mChannel->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));
// we're already connected to this server, skip login.
mState = FTP_S_PASV;
@ -646,7 +652,43 @@ nsFtpState::Process()
mInternalError = NS_ERROR_FTP_PWD;
break;
// FEAT for RFC2640 support
case FTP_S_FEAT:
rv = S_feat();
if (NS_FAILED(rv))
mInternalError = rv;
MoveToNextState(FTP_R_FEAT);
break;
case FTP_R_FEAT:
mState = R_feat();
// Don't want to overwrite a more explicit status code
if (FTP_ERROR == mState && NS_SUCCEEDED(mInternalError))
mInternalError = NS_ERROR_FAILURE;
break;
// OPTS for some non-RFC2640-compliant servers support
case FTP_S_OPTS:
rv = S_opts();
if (NS_FAILED(rv))
mInternalError = rv;
MoveToNextState(FTP_R_OPTS);
break;
case FTP_R_OPTS:
mState = R_opts();
// Don't want to overwrite a more explicit status code
if (FTP_ERROR == mState && NS_SUCCEEDED(mInternalError))
mInternalError = NS_ERROR_FAILURE;
break;
default:
;
@ -923,7 +965,7 @@ nsFtpState::R_syst() {
return FTP_ERROR;
}
return FTP_S_PWD;
return FTP_S_FEAT;
}
if (mResponseCode/100 == 5) {
@ -931,7 +973,7 @@ nsFtpState::R_syst() {
// No clue. We will just hope it is UNIX type server.
mServerType = FTP_UNIX_TYPE;
return FTP_S_PWD;
return FTP_S_FEAT;
}
return FTP_ERROR;
}
@ -1135,6 +1177,10 @@ nsFtpState::S_list() {
serverType.AppendInt(mServerType);
mCacheEntry->SetMetaDataElement("servertype", serverType.get());
nsAutoCString useUTF8;
useUTF8.AppendInt(mUseUTF8);
mCacheEntry->SetMetaDataElement("useUTF8", useUTF8.get());
// open cache entry for writing, and configure it to receive data.
if (NS_FAILED(InstallCacheListener())) {
mCacheEntry->AsyncDoom(nullptr);
@ -1551,6 +1597,39 @@ nsFtpState::R_pasv() {
return FTP_S_SIZE;
}
nsresult
nsFtpState::S_feat() {
return SendFTPCommand(NS_LITERAL_CSTRING("FEAT" CRLF));
}
FTP_STATE
nsFtpState::R_feat() {
if (mResponseCode/100 == 2) {
if (mResponseMsg.Find(NS_LITERAL_CSTRING(CRLF " UTF8" CRLF), true) > -1) {
// This FTP server supports UTF-8 encoding
mChannel->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));
mUseUTF8 = true;
return FTP_S_OPTS;
}
}
mUseUTF8 = false;
return FTP_S_PWD;
}
nsresult
nsFtpState::S_opts() {
// This command is for compatibility of old FTP spec (IETF Draft)
return SendFTPCommand(NS_LITERAL_CSTRING("OPTS UTF8 ON" CRLF));
}
FTP_STATE
nsFtpState::R_opts() {
// Ignore error code because "OPTS UTF8 ON" is for compatibility of
// FTP server using IETF draft
return FTP_S_PWD;
}
////////////////////////////////////////////////////////////////////////////////
// nsIRequest methods:
@ -1847,6 +1926,7 @@ nsFtpState::KillControlConnection()
mControlConnection->mServerType = mServerType;
mControlConnection->mPassword = mPassword;
mControlConnection->mPwd = mPwd;
mControlConnection->mUseUTF8 = mUseUTF8;
nsresult rv = NS_OK;
// Don't cache controlconnection if anonymous (bug #473371)
@ -1865,7 +1945,7 @@ nsFtpState::KillControlConnection()
class nsFtpAsyncAlert : public nsRunnable
{
public:
nsFtpAsyncAlert(nsIPrompt *aPrompter, nsACString& aResponseMsg)
nsFtpAsyncAlert(nsIPrompt *aPrompter, nsString aResponseMsg)
: mPrompter(aPrompter)
, mResponseMsg(aResponseMsg)
{
@ -1878,15 +1958,15 @@ public:
NS_IMETHOD Run()
{
if (mPrompter) {
mPrompter->Alert(nullptr, NS_ConvertASCIItoUTF16(mResponseMsg).get());
mPrompter->Alert(nullptr, mResponseMsg.get());
}
return NS_OK;
}
private:
nsCOMPtr<nsIPrompt> mPrompter;
nsCString mResponseMsg;
nsString mResponseMsg;
};
nsresult
nsFtpState::StopProcessing()
@ -1910,8 +1990,14 @@ nsFtpState::StopProcessing()
nsCOMPtr<nsIPrompt> prompter;
mChannel->GetCallback(prompter);
if (prompter) {
nsCOMPtr<nsIRunnable> alertEvent =
new nsFtpAsyncAlert(prompter, mResponseMsg);
nsCOMPtr<nsIRunnable> alertEvent;
if (mUseUTF8) {
alertEvent = new nsFtpAsyncAlert(prompter,
NS_ConvertUTF8toUTF16(mResponseMsg));
} else {
alertEvent = new nsFtpAsyncAlert(prompter,
NS_ConvertASCIItoUTF16(mResponseMsg));
}
NS_DispatchToMainThread(alertEvent, NS_DISPATCH_NORMAL);
}
}
@ -2372,6 +2458,12 @@ nsFtpState::ReadCacheEntry()
nsAutoCString serverNum(serverType.get());
nsresult err;
mServerType = serverNum.ToInteger(&err);
nsXPIDLCString charset;
mCacheEntry->GetMetaDataElement("useUTF8", getter_Copies(charset));
const char *useUTF8 = charset.get();
if (useUTF8 && atoi(useUTF8) == 1)
mChannel->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));
mChannel->PushStreamConverter("text/ftp-dir",
APPLICATION_HTTP_INDEX_FORMAT);

View File

@ -57,7 +57,9 @@ typedef enum _FTP_STATE {
FTP_S_STOR, FTP_R_STOR,
FTP_S_LIST, FTP_R_LIST,
FTP_S_PASV, FTP_R_PASV,
FTP_S_PWD, FTP_R_PWD
FTP_S_PWD, FTP_R_PWD,
FTP_S_FEAT, FTP_R_FEAT,
FTP_S_OPTS, FTP_R_OPTS
} FTP_STATE;
// higher level ftp actions
@ -129,6 +131,8 @@ private:
nsresult S_stor(); FTP_STATE R_stor();
nsresult S_pasv(); FTP_STATE R_pasv();
nsresult S_pwd(); FTP_STATE R_pwd();
nsresult S_feat(); FTP_STATE R_feat();
nsresult S_opts(); FTP_STATE R_opts();
// END: STATE METHODS
///////////////////////////////////
@ -243,6 +247,7 @@ private:
nsCOMPtr<nsIRequest> mUploadRequest;
bool mAddressChecked;
bool mServerIsIPv6;
bool mUseUTF8;
static uint32_t mSessionStartTime;

View File

@ -65,8 +65,8 @@ nsFtpControlConnection::OnInputStreamReady(nsIAsyncInputStream *stream)
nsFtpControlConnection::nsFtpControlConnection(const nsCSubstring& host,
uint32_t port)
: mServerType(0), mSessionId(gFtpHandler->GetSessionId()), mHost(host)
, mPort(port)
: mServerType(0), mSessionId(gFtpHandler->GetSessionId())
, mUseUTF8(false), mHost(host), mPort(port)
{
LOG_ALWAYS(("FTP:CC created @%p", this));
}

View File

@ -68,6 +68,7 @@ public:
int32_t mSuspendedWrite;
nsCString mPwd;
uint32_t mSessionId;
bool mUseUTF8;
private:
nsCString mHost;

View File

@ -46,7 +46,11 @@ CryptoTask::Run()
if (mThread) {
// Don't leak threads!
mThread->Shutdown(); // can't Shutdown from the thread itself, darn
mThread = nullptr;
// Don't null out mThread!
// See bug 999104. We must hold a ref to the thread across Dispatch()
// since the internal mThread ref could be released while processing
// the Dispatch(), and Dispatch/PutEvent itself doesn't hold a ref; it
// assumes the caller does.
}
}

View File

@ -42,6 +42,7 @@ public:
// Can't add 'this' as the event to run, since mThread may not be set yet
nsresult rv = NS_NewNamedThread(taskThreadName, getter_AddRefs(mThread));
if (NS_SUCCEEDED(rv)) {
// Note: event must not null out mThread!
rv = mThread->Dispatch(this, NS_DISPATCH_NORMAL);
}
return rv;

View File

@ -190,7 +190,7 @@ class MochitestRunner(MozbuildObject):
jsdebugger=False, debug_on_failure=False, start_at=None, end_at=None,
e10s=False, dmd=False, dump_output_directory=None,
dump_about_memory_after_test=False, dump_dmd_after_test=False,
install_extension=None, quiet=False, **kwargs):
install_extension=None, quiet=False, environment=[], **kwargs):
"""Runs a mochitest.
test_paths are path to tests. They can be a relative path from the
@ -314,6 +314,7 @@ class MochitestRunner(MozbuildObject):
options.dumpDMDAfterTest = dump_dmd_after_test
options.dumpOutputDirectory = dump_output_directory
options.quiet = quiet
options.environment = environment
options.failureFile = failure_file_path
if install_extension != None:
@ -515,6 +516,11 @@ def MochitestCommand(func):
help='Do not print test log lines unless a failure occurs.')
func = quiet(func)
setenv = CommandArgument('--setenv', default=[], action='append',
metavar='NAME=VALUE', dest='environment',
help="Sets the given variable in the application's environment")
func = setenv(func)
return func
def B2GCommand(func):

View File

@ -304,43 +304,56 @@ class Permissions(object):
proxy.update(user_proxy)
# TODO: this should live in a template!
# TODO: So changing the 5th line of the regex below from (\\\\\\\\d+)
# to (\\\\d+) makes this code work. Not sure why there would be this
# difference between automation.py.in and this file.
# If you must escape things in this string with backslashes, be aware
# of the multiple layers of escaping at work:
#
# - Python will unescape backslashes;
# - Writing out the prefs will escape things via JSON serialization;
# - The prefs file reader will unescape backslashes;
# - The JS engine parser will unescape backslashes.
pacURL = """data:text/plain,
var knownOrigins = (function () {
return [%(origins)s].reduce(function(t, h) { t[h] = true; return t; }, {})
})();
var uriRegex = new RegExp('^([a-z][-a-z0-9+.]*)' +
'://' +
'(?:[^/@]*@)?' +
'(.*?)' +
'(?::(\\\\d+))?/');
var defaultPortsForScheme = {
'http': 80,
'ws': 80,
'https': 443,
'wss': 443
};
var originSchemesRemap = {
'ws': 'http',
'wss': 'https'
};
var proxyForScheme = {
'http': 'PROXY %(remote)s:%(http)s',
'https': 'PROXY %(remote)s:%(https)s',
'ws': 'PROXY %(remote)s:%(ws)s',
'wss': 'PROXY %(remote)s:%(wss)s'
};
function FindProxyForURL(url, host)
{
var origins = [%(origins)s];
var regex = new RegExp('^([a-z][-a-z0-9+.]*)' +
'://' +
'(?:[^/@]*@)?' +
'(.*?)' +
'(?::(\\\\d+))?/');
var matches = regex.exec(url);
var matches = uriRegex.exec(url);
if (!matches)
return 'DIRECT';
var isHttp = matches[1] == 'http';
var isHttps = matches[1] == 'https';
var isWebSocket = matches[1] == 'ws';
var isWebSocketSSL = matches[1] == 'wss';
if (!matches[3])
{
if (isHttp | isWebSocket) matches[3] = '80';
if (isHttps | isWebSocketSSL) matches[3] = '443';
var originalScheme = matches[1];
var host = matches[2];
var port = matches[3];
if (!port && originalScheme in defaultPortsForScheme) {
port = defaultPortsForScheme[originalScheme];
}
if (isWebSocket)
matches[1] = 'http';
if (isWebSocketSSL)
matches[1] = 'https';
var schemeForOriginChecking = originSchemesRemap[originalScheme] || originalScheme;
var origin = matches[1] + '://' + matches[2] + ':' + matches[3];
if (origins.indexOf(origin) < 0)
var origin = schemeForOriginChecking + '://' + host + ':' + port;
if (!(origin in knownOrigins))
return 'DIRECT';
if (isHttp) return 'PROXY %(remote)s:%(http)s';
if (isHttps) return 'PROXY %(remote)s:%(https)s';
if (isWebSocket) return 'PROXY %(remote)s:%(ws)s';
if (isWebSocketSSL) return 'PROXY %(remote)s:%(wss)s';
return 'DIRECT';
return proxyForScheme[originalScheme] || 'DIRECT';
}""" % proxy
pacURL = "".join(pacURL.splitlines())

10
testing/mozbase/mozprofile/tests/permissions.py Normal file → Executable file
View File

@ -123,13 +123,13 @@ http://127.0.0.1:8888 privileged
self.assertEqual(user_prefs[0], ('network.proxy.type', 2))
self.assertEqual(user_prefs[1][0], 'network.proxy.autoconfig_url')
origins_decl = "var origins = ['http://mochi.test:8888', 'http://127.0.0.1:80', 'http://127.0.0.1:8888'];"
origins_decl = "var knownOrigins = (function () { return ['http://mochi.test:8888', 'http://127.0.0.1:80', 'http://127.0.0.1:8888'].reduce"
self.assertTrue(origins_decl in user_prefs[1][1])
proxy_check = ("if (isHttp) return 'PROXY mochi.test:8888';",
"if (isHttps) return 'PROXY mochi.test:4443';",
"if (isWebSocket) return 'PROXY mochi.test:4443';",
"if (isWebSocketSSL) return 'PROXY mochi.test:4443';")
proxy_check = ("'http': 'PROXY mochi.test:8888'",
"'https': 'PROXY mochi.test:4443'",
"'ws': 'PROXY mochi.test:4443'",
"'wss': 'PROXY mochi.test:4443'")
self.assertTrue(all(c in user_prefs[1][1] for c in proxy_check))
def verify_user_version(self, version):

View File

@ -298,7 +298,7 @@ PendingDBLookup::HandleEvent(const nsACString& tables)
// Blocklisting trumps allowlisting.
nsAutoCString blockList;
Preferences::GetCString(PREF_DOWNLOAD_BLOCK_TABLE, &blockList);
if (!mAllowlistOnly && FindInReadable(tables, blockList)) {
if (!mAllowlistOnly && FindInReadable(blockList, tables)) {
Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_LOCAL, BLOCK_LIST);
LOG(("Found principal %s on blocklist [this = %p]", mSpec.get(), this));
return mPendingLookup->OnComplete(true, NS_OK);
@ -306,7 +306,7 @@ PendingDBLookup::HandleEvent(const nsACString& tables)
nsAutoCString allowList;
Preferences::GetCString(PREF_DOWNLOAD_ALLOW_TABLE, &allowList);
if (FindInReadable(tables, allowList)) {
if (FindInReadable(allowList, tables)) {
Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_LOCAL, ALLOW_LIST);
LOG(("Found principal %s on allowlist [this = %p]", mSpec.get(), this));
return mPendingLookup->OnComplete(false, NS_OK);

View File

@ -463,8 +463,9 @@ nsThread::DispatchInternal(nsIRunnable *event, uint32_t flags,
if (NS_FAILED(rv))
return rv;
// Allows waiting; ensure no locks are held that would deadlock us!
while (wrapper->IsPending())
NS_ProcessNextEvent(thread);
NS_ProcessNextEvent(thread, true);
return wrapper->Result();
}
@ -539,8 +540,9 @@ nsThread::Shutdown()
// after setting mShutdownContext just before exiting.
// Process events on the current thread until we receive a shutdown ACK.
// Allows waiting; ensure no locks are held that would deadlock us!
while (!context.shutdownAck)
NS_ProcessNextEvent(context.joiningThread);
NS_ProcessNextEvent(context.joiningThread, true);
// Now, it should be safe to join without fear of dead-locking.