mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- bug 1191326 - always initialize ProxyAccessible::mOuterDoc r=lsocks (74ed8d596) - Bug 1156062 part 1a - New nsEditor::SplitNodeDeep variant; r=ehsan (a80d26ece) - minor fix (c1e5c74e3) - Bug 1172216 - Move nsStackwalk to mozglue. r=glandium (971014ffb) - Bug 1156903: Add quirk flag that causes NPN_GetValue(NPNVdocumentOrigin) to return an empty string even when it fails; r=jimm (9508b57b1) - Bug 554178 - Remove unused member variable PluginModuleChild::mUserAgent. r=jimm (a6fda391a) - Bug 1203428 - E10S for device storage API r=cyu (da575f819) - Bug 1150642 - Make mozilla_sampler_save_profile_to_file callable from lldb in Nightly builds. r=jrmuizel (bb98fafd6) - Bug 1136834 - Stop leaking markers in ProfileBuffer. (r=mstange) (b2f5f813a) - Bug 1148069 - Ensure synchronous sampling does not set JitcodeGlobalEntry's generation. (r=djvj) (f5a4dd6a4) - Bug 1181348 - Fix ARM64 toggledCall() under debug mode. r=djvj (4bbbe51a4) - Bug 1181354 - Account for initaliasedlexical in this one weird const cutout in jit::SetProperty. (r=jandem) (472179ea2) - Bug 1181558 part 0 - Remove unused SnapshotIterator constructor. r=jandem (cae21907a) - Bug 1181558 part 1 - Share the machine state between all SnapshotIterators of the same InlineFrameIterator. r=jandem (49e53a014) - Bug 1177922 - Fix a bogus assert on OOM in markSafepointAt. r=nbp (cf26143e7) - Bug 1182060 - IsObjectEscaped: Handle UnboxedPlainObject in guard shape. r=bhackett (35b6c285a) - Bug 1183051: Fix register allocations of Atomics callouts on arm vfp; r=h4writer (42d708374) - Bug 1138693 - Add comments and test. r=jandem (9619e8053) - Bug 1138693 - Add an early quit to the test if TypedObject isn't enabled. r=nbp (f6b04026e) - Bug 1180184 - Support JSOP_TOSTRING used by template strings in baseline JIT. r=jandem (8215c953b)
This commit is contained in:
@@ -306,7 +306,7 @@ public:
|
||||
protected:
|
||||
explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc) :
|
||||
mParent(nullptr), mDoc(aThisAsDoc), mWrapper(0), mID(0),
|
||||
mRole(roles::DOCUMENT)
|
||||
mRole(roles::DOCUMENT), mOuterDoc(false)
|
||||
{ MOZ_COUNT_CTOR(ProxyAccessible); }
|
||||
|
||||
protected:
|
||||
|
||||
@@ -147,7 +147,7 @@ nsCOMPtr<T>::operator=(const mozilla::dom::OwningNonNull<U>& aOther)
|
||||
return operator=(aOther.get());
|
||||
}
|
||||
|
||||
// Declared in nsRefPtr.h
|
||||
// Declared in mozilla/nsRefPtr.h
|
||||
template<class T> template<class U>
|
||||
nsRefPtr<T>::nsRefPtr(const mozilla::dom::OwningNonNull<U>& aOther)
|
||||
: nsRefPtr(aOther.get())
|
||||
|
||||
@@ -5105,6 +5105,17 @@ ContentParent::RecvEndDriverCrashGuard(const uint32_t& aGuardType)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvGetDeviceStorageLocation(const nsString& aType,
|
||||
nsString* aPath) {
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
mozilla::AndroidBridge::GetExternalPublicDirectory(aType, *aPath);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -855,6 +855,8 @@ private:
|
||||
virtual bool RecvProfile(const nsCString& aProfile) override;
|
||||
virtual bool RecvGetGraphicsDeviceInitData(DeviceInitData* aOut) override;
|
||||
|
||||
virtual bool RecvGetDeviceStorageLocation(const nsString& aType,
|
||||
nsString* aPath) override;
|
||||
// If you add strong pointers to cycle collected objects here, be sure to
|
||||
// release these objects in ShutDownProcess. See the comment there for more
|
||||
// details.
|
||||
|
||||
@@ -1068,6 +1068,9 @@ parent:
|
||||
sync GetGraphicsDeviceInitData()
|
||||
returns (DeviceInitData aData);
|
||||
|
||||
sync GetDeviceStorageLocation(nsString type)
|
||||
returns (nsString path);
|
||||
|
||||
both:
|
||||
AsyncMessage(nsString aMessage, ClonedMessageData aData,
|
||||
CpowEntry[] aCpows, Principal aPrincipal);
|
||||
|
||||
@@ -403,7 +403,9 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
|
||||
if (!CallNPN_GetValue_NPNVdocumentOrigin(&v, &result)) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
if (result == NPERR_NO_ERROR) {
|
||||
if (result == NPERR_NO_ERROR ||
|
||||
(GetQuirks() &
|
||||
PluginModuleChild::QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN)) {
|
||||
*static_cast<char**>(aValue) = ToNewCString(v);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -149,7 +149,7 @@ PluginModuleChild::PluginModuleChild(bool aIsChrome)
|
||||
MOZ_ASSERT(!gChromeInstance);
|
||||
gChromeInstance = this;
|
||||
}
|
||||
mUserAgent.SetIsVoid(true);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (aIsChrome) {
|
||||
mac_plugin_interposing::child::SetUpCocoaInterposing();
|
||||
@@ -2095,15 +2095,18 @@ PluginModuleChild::InitQuirksModes(const nsCString& aMimeType)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef OS_WIN
|
||||
if (specialType == nsPluginHost::eSpecialType_Flash) {
|
||||
mQuirks |= QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN;
|
||||
#ifdef OS_WIN
|
||||
mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK;
|
||||
mQuirks |= QUIRK_FLASH_THROTTLE_WMUSER_EVENTS;
|
||||
mQuirks |= QUIRK_FLASH_HOOK_SETLONGPTR;
|
||||
mQuirks |= QUIRK_FLASH_HOOK_GETWINDOWINFO;
|
||||
mQuirks |= QUIRK_FLASH_FIXUP_MOUSE_CAPTURE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef OS_WIN
|
||||
// QuickTime plugin usually loaded with audio/mpeg mimetype
|
||||
NS_NAMED_LITERAL_CSTRING(quicktime, "npqtplugin");
|
||||
if (FindInReadable(quicktime, mPluginFilename)) {
|
||||
|
||||
@@ -266,8 +266,12 @@ public:
|
||||
// CGContextRef we pass to it in NPP_HandleEvent(NPCocoaEventDrawRect)
|
||||
// outside of that call. See bug 804606.
|
||||
QUIRK_FLASH_AVOID_CGMODE_CRASHES = 1 << 10,
|
||||
// Work around a Flash bug where it fails to check the error code of a
|
||||
// NPN_GetValue(NPNVdocumentOrigin) call before trying to dereference
|
||||
// its char* output.
|
||||
QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN = 1 << 11,
|
||||
// Win: Addresses a Unity bug with mouse capture.
|
||||
QUIRK_UNITY_FIXUP_MOUSE_CAPTURE = 1 << 11,
|
||||
QUIRK_UNITY_FIXUP_MOUSE_CAPTURE = 1 << 12,
|
||||
};
|
||||
|
||||
int GetQuirks() { return mQuirks; }
|
||||
@@ -303,7 +307,6 @@ private:
|
||||
|
||||
PRLibrary* mLibrary;
|
||||
nsCString mPluginFilename; // UTF8
|
||||
nsCString mUserAgent;
|
||||
int mQuirks;
|
||||
|
||||
bool mIsChrome;
|
||||
|
||||
@@ -3802,6 +3802,33 @@ nsEditor::IsPreformatted(nsIDOMNode *aNode, bool *aResult)
|
||||
// a new element, for instance, if that's why you were splitting
|
||||
// the node.
|
||||
//
|
||||
int32_t
|
||||
nsEditor::SplitNodeDeep(nsIContent& aNode, nsIContent& aSplitPointParent,
|
||||
int32_t aSplitPointOffset,
|
||||
EmptyContainers aEmptyContainers,
|
||||
nsIContent** outLeftNode,
|
||||
nsIContent** outRightNode)
|
||||
{
|
||||
int32_t offset;
|
||||
nsCOMPtr<nsIDOMNode> leftNodeDOM, rightNodeDOM;
|
||||
nsresult res = SplitNodeDeep(aNode.AsDOMNode(),
|
||||
aSplitPointParent.AsDOMNode(), aSplitPointOffset, &offset,
|
||||
aEmptyContainers == EmptyContainers::no, address_of(leftNodeDOM),
|
||||
address_of(rightNodeDOM));
|
||||
NS_ENSURE_SUCCESS(res, -1);
|
||||
if (outLeftNode) {
|
||||
nsCOMPtr<nsIContent> leftNode = do_QueryInterface(leftNodeDOM);
|
||||
MOZ_ASSERT(!leftNodeDOM || leftNode);
|
||||
leftNode.forget(outLeftNode);
|
||||
}
|
||||
if (outRightNode) {
|
||||
nsCOMPtr<nsIContent> rightNode = do_QueryInterface(rightNodeDOM);
|
||||
MOZ_ASSERT(!rightNodeDOM || rightNode);
|
||||
rightNode.forget(outRightNode);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditor::SplitNodeDeep(nsIDOMNode *aNode,
|
||||
nsIDOMNode *aSplitPointParent,
|
||||
|
||||
@@ -638,13 +638,17 @@ public:
|
||||
|
||||
nsresult IsPreformatted(nsIDOMNode *aNode, bool *aResult);
|
||||
|
||||
nsresult SplitNodeDeep(nsIDOMNode *aNode,
|
||||
nsIDOMNode *aSplitPointParent,
|
||||
int32_t aSplitPointOffset,
|
||||
int32_t *outOffset,
|
||||
bool aNoEmptyContainers = false,
|
||||
nsCOMPtr<nsIDOMNode> *outLeftNode = 0,
|
||||
nsCOMPtr<nsIDOMNode> *outRightNode = 0);
|
||||
enum class EmptyContainers { no, yes };
|
||||
int32_t SplitNodeDeep(nsIContent& aNode, nsIContent& aSplitPointParent,
|
||||
int32_t aSplitPointOffset,
|
||||
EmptyContainers aEmptyContainers =
|
||||
EmptyContainers::yes,
|
||||
nsIContent** outLeftNode = nullptr,
|
||||
nsIContent** outRightNode = nullptr);
|
||||
nsresult SplitNodeDeep(nsIDOMNode* aNode, nsIDOMNode* aSplitPointParent,
|
||||
int32_t aSplitPointOffset, int32_t* outOffset, bool aNoEmptyContainers =
|
||||
false, nsCOMPtr<nsIDOMNode>* outLeftNode = nullptr, nsCOMPtr<nsIDOMNode>*
|
||||
outRightNode = nullptr);
|
||||
::DOMPoint JoinNodeDeep(nsIContent& aLeftNode, nsIContent& aRightNode);
|
||||
|
||||
nsresult GetString(const nsAString& name, nsAString& value);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
for (a of []) {}
|
||||
var log = "";
|
||||
(function() {
|
||||
for (a of [,0]) {}
|
||||
const y = "FOO";
|
||||
log += y;
|
||||
function inner() { log += y; }
|
||||
})()
|
||||
assertEq(log, "FOO");
|
||||
@@ -0,0 +1,22 @@
|
||||
if (!this.hasOwnProperty("TypedObject"))
|
||||
quit();
|
||||
|
||||
var T = TypedObject;
|
||||
var ST = new T.StructType({x:T.int32});
|
||||
function check(v) {
|
||||
return v.toSource();
|
||||
}
|
||||
function test() {
|
||||
var fake = { toSource: ST.toSource };
|
||||
try {
|
||||
check(fake);
|
||||
} catch (e) {}
|
||||
}
|
||||
test();
|
||||
var uint8 = TypedObject.uint8;
|
||||
function runTests() {
|
||||
uint8.toSource();
|
||||
}
|
||||
runTests();
|
||||
test();
|
||||
|
||||
@@ -137,8 +137,8 @@ class BailoutFrameInfo
|
||||
SnapshotOffset snapshotOffset() const {
|
||||
return snapshotOffset_;
|
||||
}
|
||||
const MachineState machineState() const {
|
||||
return machine_;
|
||||
const MachineState* machineState() const {
|
||||
return &machine_;
|
||||
}
|
||||
size_t topFrameSize() const {
|
||||
return topFrameSize_;
|
||||
|
||||
@@ -412,7 +412,7 @@ class SnapshotIteratorForBailout : public SnapshotIterator
|
||||
|
||||
public:
|
||||
SnapshotIteratorForBailout(JitActivation* activation, JitFrameIterator& iter)
|
||||
: SnapshotIterator(iter),
|
||||
: SnapshotIterator(iter, activation->bailoutData()->machineState()),
|
||||
activation_(activation),
|
||||
iter_(iter)
|
||||
{
|
||||
|
||||
@@ -3340,6 +3340,34 @@ BaselineCompiler::emit_JSOP_TOID()
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef JSString* (*ToStringFn)(JSContext*, HandleValue);
|
||||
static const VMFunction ToStringInfo = FunctionInfo<ToStringFn>(ToStringSlow);
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_TOSTRING()
|
||||
{
|
||||
// Keep top stack value in R0.
|
||||
frame.popRegsAndSync(1);
|
||||
|
||||
// Inline path for string.
|
||||
Label done;
|
||||
masm.branchTestString(Assembler::Equal, R0, &done);
|
||||
|
||||
prepareVMCall();
|
||||
|
||||
pushArg(R0);
|
||||
|
||||
// Call ToStringSlow which doesn't handle string inputs.
|
||||
if (!callVM(ToStringInfo))
|
||||
return false;
|
||||
|
||||
masm.tagValue(JSVAL_TYPE_STRING, ReturnReg, R0);
|
||||
|
||||
masm.bind(&done);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_TABLESWITCH()
|
||||
{
|
||||
|
||||
@@ -184,6 +184,7 @@ namespace jit {
|
||||
_(JSOP_RUNONCE) \
|
||||
_(JSOP_REST) \
|
||||
_(JSOP_TOID) \
|
||||
_(JSOP_TOSTRING) \
|
||||
_(JSOP_TABLESWITCH) \
|
||||
_(JSOP_ITER) \
|
||||
_(JSOP_MOREITER) \
|
||||
|
||||
@@ -410,7 +410,7 @@ class SnapshotIterator
|
||||
SnapshotReader snapshot_;
|
||||
RecoverReader recover_;
|
||||
JitFrameLayout* fp_;
|
||||
MachineState machine_;
|
||||
const MachineState* machine_;
|
||||
IonScript* ionScript_;
|
||||
RInstructionResults* instructionResults_;
|
||||
|
||||
@@ -429,17 +429,17 @@ class SnapshotIterator
|
||||
private:
|
||||
// Read a spilled register from the machine state.
|
||||
bool hasRegister(Register reg) const {
|
||||
return machine_.has(reg);
|
||||
return machine_->has(reg);
|
||||
}
|
||||
uintptr_t fromRegister(Register reg) const {
|
||||
return machine_.read(reg);
|
||||
return machine_->read(reg);
|
||||
}
|
||||
|
||||
bool hasRegister(FloatRegister reg) const {
|
||||
return machine_.has(reg);
|
||||
return machine_->has(reg);
|
||||
}
|
||||
double fromRegister(FloatRegister reg) const {
|
||||
return machine_.read(reg);
|
||||
return machine_->read(reg);
|
||||
}
|
||||
|
||||
// Read an uintptr_t from the stack.
|
||||
@@ -550,9 +550,7 @@ class SnapshotIterator
|
||||
// Connect all informations about the current script in order to recover the
|
||||
// content of baseline frames.
|
||||
|
||||
SnapshotIterator(IonScript* ionScript, SnapshotOffset snapshotOffset,
|
||||
JitFrameLayout* fp, const MachineState& machine);
|
||||
explicit SnapshotIterator(const JitFrameIterator& iter);
|
||||
SnapshotIterator(const JitFrameIterator& iter, const MachineState* machineState);
|
||||
SnapshotIterator();
|
||||
|
||||
Value read() {
|
||||
@@ -657,6 +655,9 @@ class InlineFrameIterator
|
||||
jsbytecode* pc_;
|
||||
uint32_t numActualArgs_;
|
||||
|
||||
// Register state, used by all snapshot iterators.
|
||||
MachineState machine_;
|
||||
|
||||
struct Nop {
|
||||
void operator()(const Value& v) { }
|
||||
};
|
||||
|
||||
+15
-29
@@ -353,12 +353,12 @@ JitFrameIterator::machineState() const
|
||||
|
||||
// The MachineState is used by GCs for marking call-sites.
|
||||
if (MOZ_UNLIKELY(isBailoutJS()))
|
||||
return activation_->bailoutData()->machineState();
|
||||
return *activation_->bailoutData()->machineState();
|
||||
|
||||
SafepointReader reader(ionScript(), safepoint());
|
||||
uintptr_t* spill = spillBase();
|
||||
|
||||
MachineState machine;
|
||||
|
||||
for (GeneralRegisterBackwardIterator iter(reader.allGprSpills()); iter.more(); iter++)
|
||||
machine.setRegisterLocation(*iter, --spill);
|
||||
|
||||
@@ -1163,7 +1163,7 @@ MarkBailoutFrame(JSTracer* trc, const JitFrameIterator& frame)
|
||||
|
||||
// The vector of recover instructions is already traced as part of the
|
||||
// JitActivation.
|
||||
SnapshotIterator snapIter(frame);
|
||||
SnapshotIterator snapIter(frame, frame.activation()->bailoutData()->machineState());
|
||||
|
||||
// For each instruction, we read the allocations without evaluating the
|
||||
// recover instruction, nor reconstructing the frame. We are only looking at
|
||||
@@ -1754,24 +1754,7 @@ RInstructionResults::trace(JSTracer* trc)
|
||||
}
|
||||
|
||||
|
||||
SnapshotIterator::SnapshotIterator(IonScript* ionScript, SnapshotOffset snapshotOffset,
|
||||
JitFrameLayout* fp, const MachineState& machine)
|
||||
: snapshot_(ionScript->snapshots(),
|
||||
snapshotOffset,
|
||||
ionScript->snapshotsRVATableSize(),
|
||||
ionScript->snapshotsListSize()),
|
||||
recover_(snapshot_,
|
||||
ionScript->recovers(),
|
||||
ionScript->recoversSize()),
|
||||
fp_(fp),
|
||||
machine_(machine),
|
||||
ionScript_(ionScript),
|
||||
instructionResults_(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(snapshotOffset < ionScript->snapshotsListSize());
|
||||
}
|
||||
|
||||
SnapshotIterator::SnapshotIterator(const JitFrameIterator& iter)
|
||||
SnapshotIterator::SnapshotIterator(const JitFrameIterator& iter, const MachineState* machineState)
|
||||
: snapshot_(iter.ionScript()->snapshots(),
|
||||
iter.snapshotOffset(),
|
||||
iter.ionScript()->snapshotsRVATableSize(),
|
||||
@@ -1780,7 +1763,7 @@ SnapshotIterator::SnapshotIterator(const JitFrameIterator& iter)
|
||||
iter.ionScript()->recovers(),
|
||||
iter.ionScript()->recoversSize()),
|
||||
fp_(iter.jsFrame()),
|
||||
machine_(iter.machineState()),
|
||||
machine_(machineState),
|
||||
ionScript_(iter.ionScript()),
|
||||
instructionResults_(nullptr)
|
||||
{
|
||||
@@ -2012,7 +1995,7 @@ SnapshotIterator::floatAllocationPointer(const RValueAllocation& alloc) const
|
||||
{
|
||||
switch (alloc.mode()) {
|
||||
case RValueAllocation::ANY_FLOAT_REG:
|
||||
return machine_.address(alloc.fpuReg());
|
||||
return machine_->address(alloc.fpuReg());
|
||||
|
||||
case RValueAllocation::ANY_FLOAT_STACK:
|
||||
return (FloatRegisters::RegisterContent*) AddressOfFrameSlot(fp_, alloc.stackOffset());
|
||||
@@ -2065,7 +2048,7 @@ SnapshotIterator::writeAllocationValuePayload(const RValueAllocation& alloc, Val
|
||||
break;
|
||||
|
||||
case RValueAllocation::TYPED_REG:
|
||||
machine_.write(alloc.reg2(), payload);
|
||||
machine_->write(alloc.reg2(), payload);
|
||||
break;
|
||||
|
||||
case RValueAllocation::TYPED_STACK:
|
||||
@@ -2084,7 +2067,7 @@ SnapshotIterator::writeAllocationValuePayload(const RValueAllocation& alloc, Val
|
||||
#if defined(JS_NUNBOX32)
|
||||
case RValueAllocation::UNTYPED_REG_REG:
|
||||
case RValueAllocation::UNTYPED_STACK_REG:
|
||||
machine_.write(alloc.reg2(), payload);
|
||||
machine_->write(alloc.reg2(), payload);
|
||||
break;
|
||||
|
||||
case RValueAllocation::UNTYPED_REG_STACK:
|
||||
@@ -2093,7 +2076,7 @@ SnapshotIterator::writeAllocationValuePayload(const RValueAllocation& alloc, Val
|
||||
break;
|
||||
#elif defined(JS_PUNBOX64)
|
||||
case RValueAllocation::UNTYPED_REG:
|
||||
machine_.write(alloc.reg(), v.asRawBits());
|
||||
machine_->write(alloc.reg(), v.asRawBits());
|
||||
break;
|
||||
|
||||
case RValueAllocation::UNTYPED_STACK:
|
||||
@@ -2203,7 +2186,8 @@ SnapshotIterator::initInstructionResults(MaybeReadFallback& fallback)
|
||||
// Start a new snapshot at the beginning of the JitFrameIterator. This
|
||||
// SnapshotIterator is used for evaluating the content of all recover
|
||||
// instructions. The result is then saved on the JitActivation.
|
||||
SnapshotIterator s(*fallback.frame);
|
||||
MachineState machine = fallback.frame->machineState();
|
||||
SnapshotIterator s(*fallback.frame, &machine);
|
||||
if (!s.computeInstructionResults(cx, results)) {
|
||||
|
||||
// If the evaluation failed because of OOMs, then we discard the
|
||||
@@ -2395,7 +2379,8 @@ InlineFrameIterator::InlineFrameIterator(JSContext* cx, const InlineFrameIterato
|
||||
script_(cx)
|
||||
{
|
||||
if (frame_) {
|
||||
start_ = SnapshotIterator(*frame_);
|
||||
machine_ = iter->machine_;
|
||||
start_ = SnapshotIterator(*frame_, &machine_);
|
||||
|
||||
// findNextFrame will iterate to the next frame and init. everything.
|
||||
// Therefore to settle on the same frame, we report one frame less readed.
|
||||
@@ -2412,7 +2397,8 @@ InlineFrameIterator::resetOn(const JitFrameIterator* iter)
|
||||
frameCount_ = UINT32_MAX;
|
||||
|
||||
if (iter) {
|
||||
start_ = SnapshotIterator(*iter);
|
||||
machine_ = iter->machineState();
|
||||
start_ = SnapshotIterator(*iter, &machine_);
|
||||
findNextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,10 @@ class RegisterDump
|
||||
}
|
||||
};
|
||||
|
||||
// Information needed to recover machine register state.
|
||||
// Information needed to recover machine register state. This records the
|
||||
// location of spilled register and not the content of the spilled
|
||||
// registers. Thus we can safely assume that this structure is unchanged, even
|
||||
// if the GC pointers mapped by this structure are relocated.
|
||||
class MachineState
|
||||
{
|
||||
mozilla::Array<Registers::RegisterContent*, Registers::Total> regs_;
|
||||
@@ -120,10 +123,12 @@ class MachineState
|
||||
|
||||
public:
|
||||
MachineState() {
|
||||
#ifndef JS_CODEGEN_NONE
|
||||
for (unsigned i = 0; i < Registers::Total; i++)
|
||||
regs_[i] = reinterpret_cast<Registers::RegisterContent*>(i + 0x100);
|
||||
for (unsigned i = 0; i < FloatRegisters::Total; i++)
|
||||
fpregs_[i] = reinterpret_cast<FloatRegisters::RegisterContent*>(i + 0x200);
|
||||
#endif
|
||||
}
|
||||
|
||||
static MachineState FromBailout(RegisterDump::GPRArray& regs, RegisterDump::FPUArray& fpregs);
|
||||
|
||||
@@ -224,7 +224,7 @@ IsObjectEscaped(MInstruction* ins, JSObject* objDefault)
|
||||
case MDefinition::Op_GuardShape: {
|
||||
MGuardShape* guard = def->toGuardShape();
|
||||
MOZ_ASSERT(!ins->isGuardShape());
|
||||
if (obj->as<NativeObject>().lastProperty() != guard->shape()) {
|
||||
if (obj->maybeShape() != guard->shape()) {
|
||||
JitSpewDef(JitSpew_Escape, "has a non-matching guard shape\n", guard);
|
||||
return true;
|
||||
}
|
||||
@@ -511,6 +511,8 @@ ObjectMemoryView::visitStoreFixedSlot(MStoreFixedSlot* ins)
|
||||
state_->setFixedSlot(ins->slot(), ins->value());
|
||||
ins->block()->insertBefore(ins->toInstruction(), state_);
|
||||
} else {
|
||||
// UnsafeSetReserveSlot can access baked-in slots which are guarded by
|
||||
// conditions, which are not seen by the escape analysis.
|
||||
MBail* bailout = MBail::New(alloc_, Bailout_Inevitable);
|
||||
ins->block()->insertBefore(ins, bailout);
|
||||
}
|
||||
@@ -530,6 +532,8 @@ ObjectMemoryView::visitLoadFixedSlot(MLoadFixedSlot* ins)
|
||||
if (state_->hasFixedSlot(ins->slot())) {
|
||||
ins->replaceAllUsesWith(state_->getFixedSlot(ins->slot()));
|
||||
} else {
|
||||
// UnsafeGetReserveSlot can access baked-in slots which are guarded by
|
||||
// conditions, which are not seen by the escape analysis.
|
||||
MBail* bailout = MBail::New(alloc_, Bailout_Inevitable);
|
||||
ins->block()->insertBefore(ins, bailout);
|
||||
ins->replaceAllUsesWith(undefinedVal_);
|
||||
@@ -572,6 +576,8 @@ ObjectMemoryView::visitStoreSlot(MStoreSlot* ins)
|
||||
state_->setDynamicSlot(ins->slot(), ins->value());
|
||||
ins->block()->insertBefore(ins->toInstruction(), state_);
|
||||
} else {
|
||||
// UnsafeSetReserveSlot can access baked-in slots which are guarded by
|
||||
// conditions, which are not seen by the escape analysis.
|
||||
MBail* bailout = MBail::New(alloc_, Bailout_Inevitable);
|
||||
ins->block()->insertBefore(ins, bailout);
|
||||
}
|
||||
@@ -595,6 +601,8 @@ ObjectMemoryView::visitLoadSlot(MLoadSlot* ins)
|
||||
if (state_->hasDynamicSlot(ins->slot())) {
|
||||
ins->replaceAllUsesWith(state_->getDynamicSlot(ins->slot()));
|
||||
} else {
|
||||
// UnsafeGetReserveSlot can access baked-in slots which are guarded by
|
||||
// conditions, which are not seen by the escape analysis.
|
||||
MBail* bailout = MBail::New(alloc_, Bailout_Inevitable);
|
||||
ins->block()->insertBefore(ins, bailout);
|
||||
ins->replaceAllUsesWith(undefinedVal_);
|
||||
|
||||
@@ -435,7 +435,7 @@ SetProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValu
|
||||
|
||||
JSOp op = JSOp(*pc);
|
||||
|
||||
if (op == JSOP_SETALIASEDVAR) {
|
||||
if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL) {
|
||||
// Aliased var assigns ignore readonly attributes on the property, as
|
||||
// required for initializing 'const' closure variables.
|
||||
Shape* shape = obj->as<NativeObject>().lookup(cx, name);
|
||||
|
||||
@@ -659,10 +659,10 @@ LIRGeneratorARM::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins)
|
||||
|
||||
if (byteSize(ins->accessType()) != 4 && !HasLDSTREXBHD()) {
|
||||
LAsmJSCompareExchangeCallout* lir =
|
||||
new(alloc()) LAsmJSCompareExchangeCallout(useRegister(ptr),
|
||||
useRegister(ins->oldValue()),
|
||||
useRegister(ins->newValue()));
|
||||
defineFixed(lir, ins, LAllocation(AnyRegister(ReturnReg)));
|
||||
new(alloc()) LAsmJSCompareExchangeCallout(useRegisterAtStart(ptr),
|
||||
useRegisterAtStart(ins->oldValue()),
|
||||
useRegisterAtStart(ins->newValue()));
|
||||
defineReturn(lir, ins);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -680,14 +680,12 @@ LIRGeneratorARM::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins)
|
||||
MOZ_ASSERT(ins->ptr()->type() == MIRType_Int32);
|
||||
MOZ_ASSERT(ins->accessType() < Scalar::Float32);
|
||||
|
||||
const LAllocation ptr = useRegister(ins->ptr());
|
||||
const LAllocation value = useRegister(ins->value());
|
||||
const LAllocation ptr = useRegisterAtStart(ins->ptr());
|
||||
const LAllocation value = useRegisterAtStart(ins->value());
|
||||
|
||||
if (byteSize(ins->accessType()) < 4 && !HasLDSTREXBHD()) {
|
||||
// Call out on ARMv6.
|
||||
defineFixed(new(alloc()) LAsmJSAtomicExchangeCallout(ptr, value),
|
||||
ins,
|
||||
LAllocation(AnyRegister(ReturnReg)));
|
||||
defineReturn(new(alloc()) LAsmJSAtomicExchangeCallout(ptr, value), ins);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -704,8 +702,9 @@ LIRGeneratorARM::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins)
|
||||
|
||||
if (byteSize(ins->accessType()) != 4 && !HasLDSTREXBHD()) {
|
||||
LAsmJSAtomicBinopCallout* lir =
|
||||
new(alloc()) LAsmJSAtomicBinopCallout(useRegister(ptr), useRegister(ins->value()));
|
||||
defineFixed(lir, ins, LAllocation(AnyRegister(ReturnReg)));
|
||||
new(alloc()) LAsmJSAtomicBinopCallout(useRegisterAtStart(ptr),
|
||||
useRegisterAtStart(ins->value()));
|
||||
defineReturn(lir, ins);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2870,6 +2870,10 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
||||
// Emit a BLR or NOP instruction. ToggleCall can be used to patch
|
||||
// this instruction.
|
||||
CodeOffsetLabel toggledCall(JitCode* target, bool enabled) {
|
||||
// The returned offset must be to the first instruction generated,
|
||||
// for the debugger to match offset with Baseline's pcMappingEntries_.
|
||||
BufferOffset offset = nextOffset();
|
||||
|
||||
// TODO: Random pool insertion between instructions below is terrible.
|
||||
// Unfortunately, we can't forbid pool prevention, because we're trying
|
||||
// to add an entry to a pool. So as a temporary fix, just flush the pool
|
||||
@@ -2879,7 +2883,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
||||
|
||||
syncStackPtr();
|
||||
|
||||
BufferOffset offset = nextOffset();
|
||||
BufferOffset loadOffset;
|
||||
{
|
||||
vixl::UseScratchRegisterScope temps(this);
|
||||
|
||||
@@ -1052,7 +1052,7 @@ CodeGeneratorShared::markSafepoint(LInstruction* ins)
|
||||
void
|
||||
CodeGeneratorShared::markSafepointAt(uint32_t offset, LInstruction* ins)
|
||||
{
|
||||
MOZ_ASSERT_IF(!safepointIndices_.empty(),
|
||||
MOZ_ASSERT_IF(!safepointIndices_.empty() && !masm.oom(),
|
||||
offset - safepointIndices_.back().displacement() >= sizeof(uint32_t));
|
||||
masm.propagateOOM(safepointIndices_.append(SafepointIndex(offset, ins->safepoint())));
|
||||
}
|
||||
|
||||
+14
-31
@@ -27,7 +27,7 @@
|
||||
#endif
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Vector.h"
|
||||
@@ -117,7 +117,7 @@ static bool gIsDMDInitialized = false;
|
||||
// - Indirect allocations in js::{Vector,HashSet,HashMap} -- this class serves
|
||||
// as their AllocPolicy.
|
||||
//
|
||||
// - Other indirect allocations (e.g. NS_StackWalk) -- see the comments on
|
||||
// - Other indirect allocations (e.g. MozStackWalk) -- see the comments on
|
||||
// Thread::mBlockIntercepts and in replace_malloc for how these work.
|
||||
//
|
||||
// It would be nice if we could use the InfallibleAllocPolicy from mozalloc,
|
||||
@@ -504,7 +504,7 @@ class Thread
|
||||
// When true, this blocks intercepts, which allows malloc interception
|
||||
// functions to themselves call malloc. (Nb: for direct calls to malloc we
|
||||
// can just use InfallibleAllocPolicy::{malloc_,new_}, but we sometimes
|
||||
// indirectly call vanilla malloc via functions like NS_StackWalk.)
|
||||
// indirectly call vanilla malloc via functions like MozStackWalk.)
|
||||
bool mBlockIntercepts;
|
||||
|
||||
Thread()
|
||||
@@ -727,40 +727,23 @@ StackTrace::Get(Thread* aT)
|
||||
MOZ_ASSERT(gStateLock->IsLocked());
|
||||
MOZ_ASSERT(aT->InterceptsAreBlocked());
|
||||
|
||||
// On Windows, NS_StackWalk can acquire a lock from the shared library
|
||||
// On Windows, MozStackWalk can acquire a lock from the shared library
|
||||
// loader. Another thread might call malloc while holding that lock (when
|
||||
// loading a shared library). So we can't be in gStateLock during the call
|
||||
// to NS_StackWalk. For details, see
|
||||
// to MozStackWalk. For details, see
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=374829#c8
|
||||
// On Linux, something similar can happen; see bug 824340.
|
||||
// So let's just release it on all platforms.
|
||||
nsresult rv;
|
||||
StackTrace tmp;
|
||||
{
|
||||
AutoUnlockState unlock;
|
||||
uint32_t skipFrames = 2;
|
||||
rv = NS_StackWalk(StackWalkCallback, skipFrames,
|
||||
gOptions->MaxFrames(), &tmp, 0, nullptr);
|
||||
}
|
||||
|
||||
if (rv == NS_OK) {
|
||||
// Handle the common case first. All is ok. Nothing to do.
|
||||
} else if (rv == NS_ERROR_NOT_IMPLEMENTED || rv == NS_ERROR_FAILURE) {
|
||||
tmp.mLength = 0;
|
||||
} else if (rv == NS_ERROR_UNEXPECTED) {
|
||||
// XXX: This |rv| only happens on Mac, and it indicates that we're handling
|
||||
// a call to malloc that happened inside a mutex-handling function. Any
|
||||
// attempt to create a semaphore (which can happen in printf) could
|
||||
// deadlock.
|
||||
//
|
||||
// However, the most complex thing DMD does after Get() returns is to put
|
||||
// something in a hash table, which might call
|
||||
// InfallibleAllocPolicy::malloc_. I'm not yet sure if this needs special
|
||||
// handling, hence the forced abort. Sorry. If you hit this, please file
|
||||
// a bug and CC nnethercote.
|
||||
MOZ_CRASH("unexpected case in StackTrace::Get()");
|
||||
} else {
|
||||
MOZ_CRASH("impossible case in StackTrace::Get()");
|
||||
if (MozStackWalk(StackWalkCallback, skipFrames,
|
||||
gOptions->MaxFrames(), &tmp, 0, nullptr)) {
|
||||
// Handle the common case first. All is ok. Nothing to do.
|
||||
} else {
|
||||
tmp.mLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
StackTraceTable::AddPtr p = gStackTraceTable->lookupForAdd(&tmp);
|
||||
@@ -1224,7 +1207,7 @@ replace_malloc(size_t aSize)
|
||||
Thread* t = Thread::Fetch();
|
||||
if (t->InterceptsAreBlocked()) {
|
||||
// Intercepts are blocked, which means this must be a call to malloc
|
||||
// triggered indirectly by DMD (e.g. via NS_StackWalk). Be infallible.
|
||||
// triggered indirectly by DMD (e.g. via MozStackWalk). Be infallible.
|
||||
return InfallibleAllocPolicy::malloc_(aSize);
|
||||
}
|
||||
|
||||
@@ -1530,9 +1513,9 @@ Init(const malloc_table_t* aMallocTable)
|
||||
// (prior to the creation of any mutexes, apparently) otherwise we can get
|
||||
// hangs when getting stack traces (bug 821577). But
|
||||
// StackWalkInitCriticalAddress() isn't exported from xpcom/, so instead we
|
||||
// just call NS_StackWalk, because that calls StackWalkInitCriticalAddress().
|
||||
// just call MozStackWalk, because that calls StackWalkInitCriticalAddress().
|
||||
// See the comment above StackWalkInitCriticalAddress() for more details.
|
||||
(void)NS_StackWalk(NopStackWalkCallback, /* skipFrames */ 0,
|
||||
(void)MozStackWalk(NopStackWalkCallback, /* skipFrames */ 0,
|
||||
/* maxFrames */ 1, nullptr, 0, nullptr);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ EXPORTS += [
|
||||
SOURCES += [
|
||||
'../../../mfbt/HashFunctions.cpp',
|
||||
'../../../mfbt/JSONWriter.cpp',
|
||||
'../../../xpcom/base/nsStackWalk.cpp',
|
||||
'../../../mozglue/misc/StackWalk.cpp',
|
||||
'DMD.cpp',
|
||||
]
|
||||
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#include "nsStackWalkPrivate.h"
|
||||
|
||||
#include "nsStackWalk.h"
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
@@ -38,16 +35,16 @@ static CriticalAddress gCriticalAddress;
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#define NSSTACKWALK_SUPPORTS_MACOSX \
|
||||
#define MOZ_STACKWALK_SUPPORTS_MACOSX \
|
||||
(defined(XP_DARWIN) && \
|
||||
(defined(__i386) || defined(__ppc__) || defined(HAVE__UNWIND_BACKTRACE)))
|
||||
|
||||
#define NSSTACKWALK_SUPPORTS_LINUX \
|
||||
#define MOZ_STACKWALK_SUPPORTS_LINUX \
|
||||
(defined(linux) && \
|
||||
((defined(__GNUC__) && (defined(__i386) || defined(PPC))) || \
|
||||
defined(HAVE__UNWIND_BACKTRACE)))
|
||||
|
||||
#if NSSTACKWALK_SUPPORTS_MACOSX
|
||||
#if MOZ_STACKWALK_SUPPORTS_MACOSX
|
||||
#include <pthread.h>
|
||||
#include <sys/errno.h>
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
@@ -110,7 +107,7 @@ my_malloc_logger(uint32_t aType,
|
||||
// On Leopard dladdr returns the wrong value for "new_sem_from_pool". The
|
||||
// stack shows up as having two pthread_cond_wait$UNIX2003 frames.
|
||||
const char* name = "new_sem_from_pool";
|
||||
NS_StackWalk(stack_callback, /* skipFrames */ 0, /* maxFrames */ 0,
|
||||
MozStackWalk(stack_callback, /* skipFrames */ 0, /* maxFrames */ 0,
|
||||
const_cast<char*>(name), 0, nullptr);
|
||||
}
|
||||
|
||||
@@ -121,7 +118,7 @@ my_malloc_logger(uint32_t aType,
|
||||
// function during NS_LogInit() ensures that we meet the first criterion, and
|
||||
// running this function during the stack walking functions ensures we meet the
|
||||
// second criterion.
|
||||
void
|
||||
MFBT_API void
|
||||
StackWalkInitCriticalAddress()
|
||||
{
|
||||
if (gCriticalAddress.mInit) {
|
||||
@@ -181,7 +178,7 @@ IsCriticalAddress(void* aPC)
|
||||
// We still initialize gCriticalAddress.mInit so that this code behaves
|
||||
// the same on all platforms. Otherwise a failure to init would be visible
|
||||
// only on OS X.
|
||||
void
|
||||
MFBT_API void
|
||||
StackWalkInitCriticalAddress()
|
||||
{
|
||||
gCriticalAddress.mInit = true;
|
||||
@@ -190,15 +187,12 @@ StackWalkInitCriticalAddress()
|
||||
|
||||
#if defined(_WIN32) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_IA64)) // WIN32 x86 stack walking code
|
||||
|
||||
#include "nscore.h"
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include "plstr.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "nspr.h"
|
||||
#include <imagehlp.h>
|
||||
// We need a way to know if we are building for WXP (or later), as if we are, we
|
||||
// need to use the newer 64-bit APIs. API_VERSION_NUMBER seems to fit the bill.
|
||||
@@ -512,8 +506,8 @@ WalkStackThread(void* aData)
|
||||
* whose in memory address doesn't match its in-file address.
|
||||
*/
|
||||
|
||||
XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
MFBT_API bool
|
||||
MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
uint32_t aMaxFrames, void* aClosure, uintptr_t aThread,
|
||||
void* aPlatformData)
|
||||
{
|
||||
@@ -524,7 +518,7 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
struct WalkStackData data;
|
||||
|
||||
if (!EnsureWalkThreadReady()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE currentThread = ::GetCurrentThread();
|
||||
@@ -542,7 +536,7 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
if (data.walkCallingThread) {
|
||||
PrintError("DuplicateHandle (process)");
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!::DuplicateHandle(::GetCurrentProcess(),
|
||||
@@ -553,7 +547,7 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
if (data.walkCallingThread) {
|
||||
PrintError("DuplicateHandle (thread)");
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
return false;
|
||||
}
|
||||
|
||||
data.skipFrames = aSkipFrames;
|
||||
@@ -622,7 +616,7 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
(*aCallback)(i + 1, data.pcs[i], data.sps[i], aClosure);
|
||||
}
|
||||
|
||||
return data.pc_count == 0 ? NS_ERROR_FAILURE : NS_OK;
|
||||
return data.pc_count != 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -772,8 +766,8 @@ EnsureSymInitialized()
|
||||
}
|
||||
|
||||
|
||||
XPCOM_API(nsresult)
|
||||
NS_DescribeCodeAddress(void* aPC, nsCodeAddressDetails* aDetails)
|
||||
MFBT_API bool
|
||||
MozDescribeCodeAddress(void* aPC, MozCodeAddressDetails* aDetails)
|
||||
{
|
||||
aDetails->library[0] = '\0';
|
||||
aDetails->loffset = 0;
|
||||
@@ -783,7 +777,7 @@ NS_DescribeCodeAddress(void* aPC, nsCodeAddressDetails* aDetails)
|
||||
aDetails->foffset = 0;
|
||||
|
||||
if (!EnsureSymInitialized()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE myProcess = ::GetCurrentProcess();
|
||||
@@ -804,12 +798,12 @@ NS_DescribeCodeAddress(void* aPC, nsCodeAddressDetails* aDetails)
|
||||
modInfoRes = SymGetModuleInfoEspecial64(myProcess, addr, &modInfo, &lineInfo);
|
||||
|
||||
if (modInfoRes) {
|
||||
PL_strncpyz(aDetails->library, modInfo.ModuleName,
|
||||
strncpy(aDetails->library, modInfo.ModuleName,
|
||||
sizeof(aDetails->library));
|
||||
aDetails->loffset = (char*)aPC - (char*)modInfo.BaseOfImage;
|
||||
|
||||
if (lineInfo.FileName) {
|
||||
PL_strncpyz(aDetails->filename, lineInfo.FileName,
|
||||
strncpy(aDetails->filename, lineInfo.FileName,
|
||||
sizeof(aDetails->filename));
|
||||
aDetails->lineno = lineInfo.LineNumber;
|
||||
}
|
||||
@@ -825,23 +819,21 @@ NS_DescribeCodeAddress(void* aPC, nsCodeAddressDetails* aDetails)
|
||||
ok = SymFromAddr(myProcess, addr, &displacement, pSymbol);
|
||||
|
||||
if (ok) {
|
||||
PL_strncpyz(aDetails->function, pSymbol->Name,
|
||||
strncpy(aDetails->function, pSymbol->Name,
|
||||
sizeof(aDetails->function));
|
||||
aDetails->foffset = static_cast<ptrdiff_t>(displacement);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&gDbgHelpCS); // release our lock
|
||||
return NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// i386 or PPC Linux stackwalking code
|
||||
#elif HAVE_DLADDR && (HAVE__UNWIND_BACKTRACE || NSSTACKWALK_SUPPORTS_LINUX || NSSTACKWALK_SUPPORTS_MACOSX)
|
||||
#elif HAVE_DLADDR && (HAVE__UNWIND_BACKTRACE || MOZ_STACKWALK_SUPPORTS_LINUX || MOZ_STACKWALK_SUPPORTS_MACOSX)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "nscore.h"
|
||||
#include <stdio.h>
|
||||
#include "plstr.h"
|
||||
|
||||
// On glibc 2.1, the Dl_info api defined in <dlfcn.h> is only exposed
|
||||
// if __USE_GNU is defined. I suppose its some kind of standards
|
||||
@@ -868,7 +860,7 @@ void DemangleSymbol(const char* aSymbol,
|
||||
char* demangled = abi::__cxa_demangle(aSymbol, 0, 0, 0);
|
||||
|
||||
if (demangled) {
|
||||
PL_strncpyz(aBuffer, demangled, aBufLen);
|
||||
strncpy(aBuffer, demangled, aBufLen);
|
||||
free(demangled);
|
||||
}
|
||||
#endif // MOZ_DEMANGLE_SYMBOLS
|
||||
@@ -884,8 +876,8 @@ void DemangleSymbol(const char* aSymbol,
|
||||
extern MOZ_EXPORT void* __libc_stack_end; // from ld-linux.so
|
||||
#endif
|
||||
namespace mozilla {
|
||||
nsresult
|
||||
FramePointerStackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
bool
|
||||
FramePointerStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
uint32_t aMaxFrames, void* aClosure, void** bp,
|
||||
void* aStackEnd)
|
||||
{
|
||||
@@ -915,7 +907,7 @@ FramePointerStackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
bp += 2;
|
||||
#endif
|
||||
if (IsCriticalAddress(pc)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
return false;
|
||||
}
|
||||
if (--skip < 0) {
|
||||
// Assume that the SP points to the BP of the function
|
||||
@@ -930,16 +922,16 @@ FramePointerStackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
}
|
||||
bp = next;
|
||||
}
|
||||
return numFrames == 0 ? NS_ERROR_FAILURE : NS_OK;
|
||||
return numFrames != 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define X86_OR_PPC (defined(__i386) || defined(PPC) || defined(__ppc__))
|
||||
#if X86_OR_PPC && (NSSTACKWALK_SUPPORTS_MACOSX || NSSTACKWALK_SUPPORTS_LINUX) // i386 or PPC Linux or Mac stackwalking code
|
||||
#if X86_OR_PPC && (MOZ_STACKWALK_SUPPORTS_MACOSX || MOZ_STACKWALK_SUPPORTS_LINUX) // i386 or PPC Linux or Mac stackwalking code
|
||||
|
||||
XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
MFBT_API bool
|
||||
MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
uint32_t aMaxFrames, void* aClosure, uintptr_t aThread,
|
||||
void* aPlatformData)
|
||||
{
|
||||
@@ -975,7 +967,7 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
|
||||
struct unwind_info
|
||||
{
|
||||
NS_WalkStackCallback callback;
|
||||
MozWalkStackCallback callback;
|
||||
int skip;
|
||||
int maxFrames;
|
||||
int numFrames;
|
||||
@@ -1007,8 +999,8 @@ unwind_callback(struct _Unwind_Context* context, void* closure)
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
MFBT_API bool
|
||||
MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
uint32_t aMaxFrames, void* aClosure, uintptr_t aThread,
|
||||
void* aPlatformData)
|
||||
{
|
||||
@@ -1034,15 +1026,15 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
// is to make unwind_callback return something other than _URC_NO_REASON,
|
||||
// which causes _Unwind_Backtrace to return a non-success code.
|
||||
if (info.isCriticalAbort) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
return false;
|
||||
}
|
||||
return info.numFrames == 0 ? NS_ERROR_FAILURE : NS_OK;
|
||||
return info.numFrames != 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
XPCOM_API(nsresult)
|
||||
NS_DescribeCodeAddress(void* aPC, nsCodeAddressDetails* aDetails)
|
||||
bool MFBT_API
|
||||
MozDescribeCodeAddress(void* aPC, MozCodeAddressDetails* aDetails)
|
||||
{
|
||||
aDetails->library[0] = '\0';
|
||||
aDetails->loffset = 0;
|
||||
@@ -1054,51 +1046,51 @@ NS_DescribeCodeAddress(void* aPC, nsCodeAddressDetails* aDetails)
|
||||
Dl_info info;
|
||||
int ok = dladdr(aPC, &info);
|
||||
if (!ok) {
|
||||
return NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
PL_strncpyz(aDetails->library, info.dli_fname, sizeof(aDetails->library));
|
||||
strncpy(aDetails->library, info.dli_fname, sizeof(aDetails->library));
|
||||
aDetails->loffset = (char*)aPC - (char*)info.dli_fbase;
|
||||
|
||||
const char* symbol = info.dli_sname;
|
||||
if (!symbol || symbol[0] == '\0') {
|
||||
return NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
DemangleSymbol(symbol, aDetails->function, sizeof(aDetails->function));
|
||||
|
||||
if (aDetails->function[0] == '\0') {
|
||||
// Just use the mangled symbol if demangling failed.
|
||||
PL_strncpyz(aDetails->function, symbol, sizeof(aDetails->function));
|
||||
strncpy(aDetails->function, symbol, sizeof(aDetails->function));
|
||||
}
|
||||
|
||||
aDetails->foffset = (char*)aPC - (char*)info.dli_saddr;
|
||||
return NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
#else // unsupported platform.
|
||||
|
||||
XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
MFBT_API bool
|
||||
MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
uint32_t aMaxFrames, void* aClosure, uintptr_t aThread,
|
||||
void* aPlatformData)
|
||||
{
|
||||
MOZ_ASSERT(!aThread);
|
||||
MOZ_ASSERT(!aPlatformData);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
nsresult
|
||||
FramePointerStackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
MFBT_API bool
|
||||
FramePointerStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
void* aClosure, void** aBp)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
XPCOM_API(nsresult)
|
||||
NS_DescribeCodeAddress(void* aPC, nsCodeAddressDetails* aDetails)
|
||||
MFBT_API bool
|
||||
MozDescribeCodeAddress(void* aPC, MozCodeAddressDetails* aDetails)
|
||||
{
|
||||
aDetails->library[0] = '\0';
|
||||
aDetails->loffset = 0;
|
||||
@@ -1106,24 +1098,24 @@ NS_DescribeCodeAddress(void* aPC, nsCodeAddressDetails* aDetails)
|
||||
aDetails->lineno = 0;
|
||||
aDetails->function[0] = '\0';
|
||||
aDetails->foffset = 0;
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
XPCOM_API(void)
|
||||
NS_FormatCodeAddressDetails(char* aBuffer, uint32_t aBufferSize,
|
||||
MFBT_API void
|
||||
MozFormatCodeAddressDetails(char* aBuffer, uint32_t aBufferSize,
|
||||
uint32_t aFrameNumber, void* aPC,
|
||||
const nsCodeAddressDetails* aDetails)
|
||||
const MozCodeAddressDetails* aDetails)
|
||||
{
|
||||
NS_FormatCodeAddress(aBuffer, aBufferSize,
|
||||
MozFormatCodeAddress(aBuffer, aBufferSize,
|
||||
aFrameNumber, aPC, aDetails->function,
|
||||
aDetails->library, aDetails->loffset,
|
||||
aDetails->filename, aDetails->lineno);
|
||||
}
|
||||
|
||||
XPCOM_API(void)
|
||||
NS_FormatCodeAddress(char* aBuffer, uint32_t aBufferSize, uint32_t aFrameNumber,
|
||||
MFBT_API void
|
||||
MozFormatCodeAddress(char* aBuffer, uint32_t aBufferSize, uint32_t aFrameNumber,
|
||||
const void* aPC, const char* aFunction,
|
||||
const char* aLibrary, ptrdiff_t aLOffset,
|
||||
const char* aFileName, uint32_t aLineNo)
|
||||
@@ -6,20 +6,16 @@
|
||||
|
||||
/* API for getting a stack trace of the C/C++ stack on the current thread */
|
||||
|
||||
#ifndef nsStackWalk_h_
|
||||
#define nsStackWalk_h_
|
||||
#ifndef mozilla_StackWalk_h
|
||||
#define mozilla_StackWalk_h
|
||||
|
||||
/* WARNING: This file is intended to be included from C or C++ files. */
|
||||
|
||||
#include "nscore.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The callback for NS_StackWalk.
|
||||
* The callback for MozStackWalk.
|
||||
*
|
||||
* @param aFrameNumber The frame number (starts at 1, not 0).
|
||||
* @param aPC The program counter value.
|
||||
@@ -27,20 +23,20 @@ extern "C" {
|
||||
* pointer will be pointing to when the execution returns
|
||||
* to executing that at aPC. If no approximation can
|
||||
* be made it will be nullptr.
|
||||
* @param aClosure Extra data passed in via NS_StackWalk().
|
||||
* @param aClosure Extra data passed in via MozStackWalk().
|
||||
*/
|
||||
typedef void
|
||||
(*NS_WalkStackCallback)(uint32_t aFrameNumber, void* aPC, void* aSP,
|
||||
(*MozWalkStackCallback)(uint32_t aFrameNumber, void* aPC, void* aSP,
|
||||
void* aClosure);
|
||||
|
||||
/**
|
||||
* Call aCallback for the C/C++ stack frames on the current thread, from
|
||||
* the caller of NS_StackWalk to main (or above).
|
||||
* the caller of MozStackWalk to main (or above).
|
||||
*
|
||||
* @param aCallback Callback function, called once per frame.
|
||||
* @param aSkipFrames Number of initial frames to skip. 0 means that
|
||||
* the first callback will be for the caller of
|
||||
* NS_StackWalk.
|
||||
* MozStackWalk.
|
||||
* @param aMaxFrames Maximum number of frames to trace. 0 means no limit.
|
||||
* @param aClosure Caller-supplied data passed through to aCallback.
|
||||
* @param aThread The thread for which the stack is to be retrieved.
|
||||
@@ -53,27 +49,14 @@ typedef void
|
||||
* CONTEXT on Windows and should not be passed on other
|
||||
* platforms.
|
||||
*
|
||||
* Return values:
|
||||
* - NS_ERROR_NOT_IMPLEMENTED. Occurs on platforms where it is unimplemented.
|
||||
*
|
||||
* - NS_ERROR_UNEXPECTED. Occurs when the stack indicates that the thread
|
||||
* is in a very dangerous situation (e.g., holding sem_pool_lock in Mac OS X
|
||||
* pthreads code). Callers should then bail out immediately.
|
||||
*
|
||||
* - NS_ERROR_FAILURE. Occurs when stack walking completely failed, i.e.
|
||||
* aCallback was never called.
|
||||
*
|
||||
* - NS_OK. Occurs when stack walking succeeded, i.e. aCallback was called at
|
||||
* least once (and there was no need to exit with NS_ERROR_UNEXPECTED).
|
||||
*
|
||||
* May skip some stack frames due to compiler optimizations or code
|
||||
* generation.
|
||||
*
|
||||
* Note: this (and other helper methods) will only be available when
|
||||
* MOZ_STACKWALKING is defined, so any new consumers must #if based on that.
|
||||
*/
|
||||
XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
MFBT_API bool
|
||||
MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
uint32_t aMaxFrames, void* aClosure, uintptr_t aThread,
|
||||
void* aPlatformData);
|
||||
|
||||
@@ -99,7 +82,7 @@ typedef struct
|
||||
*/
|
||||
char function[256];
|
||||
ptrdiff_t foffset;
|
||||
} nsCodeAddressDetails;
|
||||
} MozCodeAddressDetails;
|
||||
|
||||
/**
|
||||
* For a given pointer to code, fill in the pieces of information used
|
||||
@@ -108,8 +91,8 @@ typedef struct
|
||||
* @param aPC The code address.
|
||||
* @param aDetails A structure to be filled in with the result.
|
||||
*/
|
||||
XPCOM_API(nsresult)
|
||||
NS_DescribeCodeAddress(void* aPC, nsCodeAddressDetails* aDetails);
|
||||
MFBT_API bool
|
||||
MozDescribeCodeAddress(void* aPC, MozCodeAddressDetails* aDetails);
|
||||
|
||||
/**
|
||||
* Format the information about a code address in a format suitable for
|
||||
@@ -137,15 +120,15 @@ NS_DescribeCodeAddress(void* aPC, nsCodeAddressDetails* aDetails);
|
||||
* @param aFileName The filename. Possibly null or the empty string.
|
||||
* @param aLineNo The line number. Possibly zero.
|
||||
*/
|
||||
XPCOM_API(void)
|
||||
NS_FormatCodeAddress(char* aBuffer, uint32_t aBufferSize, uint32_t aFrameNumber,
|
||||
MFBT_API void
|
||||
MozFormatCodeAddress(char* aBuffer, uint32_t aBufferSize, uint32_t aFrameNumber,
|
||||
const void* aPC, const char* aFunction,
|
||||
const char* aLibrary, ptrdiff_t aLOffset,
|
||||
const char* aFileName, uint32_t aLineNo);
|
||||
|
||||
/**
|
||||
* Format the information about a code address in the same fashion as
|
||||
* NS_FormatCodeAddress.
|
||||
* MozFormatCodeAddress.
|
||||
*
|
||||
* @param aBuffer A string to be filled in with the description.
|
||||
* The string will always be null-terminated.
|
||||
@@ -156,15 +139,27 @@ NS_FormatCodeAddress(char* aBuffer, uint32_t aBufferSize, uint32_t aFrameNumber,
|
||||
* is the terminating null.
|
||||
* @param aFrameNumber The frame number.
|
||||
* @param aPC The code address.
|
||||
* @param aDetails The value filled in by NS_DescribeCodeAddress(aPC).
|
||||
* @param aDetails The value filled in by MozDescribeCodeAddress(aPC).
|
||||
*/
|
||||
XPCOM_API(void)
|
||||
NS_FormatCodeAddressDetails(char* aBuffer, uint32_t aBufferSize,
|
||||
MFBT_API void
|
||||
MozFormatCodeAddressDetails(char* aBuffer, uint32_t aBufferSize,
|
||||
uint32_t aFrameNumber, void* aPC,
|
||||
const nsCodeAddressDetails* aDetails);
|
||||
const MozCodeAddressDetails* aDetails);
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MFBT_API bool
|
||||
FramePointerStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
uint32_t aMaxFrames, void* aClosure, void** aBp,
|
||||
void* aStackEnd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !defined(nsStackWalk_h_) */
|
||||
/**
|
||||
* Initialize the critical sections for this platform so that we can
|
||||
* abort stack walks when needed.
|
||||
*/
|
||||
MFBT_API void
|
||||
StackWalkInitCriticalAddress(void);
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
FINAL_LIBRARY = 'mozglue'
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'StackWalk.h',
|
||||
'TimeStamp.h',
|
||||
]
|
||||
|
||||
@@ -26,6 +27,7 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
SOURCES += [
|
||||
'TimeStamp_windows.cpp',
|
||||
]
|
||||
OS_LIBS += ['dbghelp']
|
||||
elif CONFIG['HAVE_CLOCK_MONOTONIC']:
|
||||
SOURCES += [
|
||||
'TimeStamp_posix.cpp',
|
||||
@@ -37,4 +39,14 @@ elif CONFIG['OS_ARCH'] == 'Darwin':
|
||||
elif CONFIG['COMPILE_ENVIRONMENT']:
|
||||
error('No TimeStamp implementation on this platform. Build will not succeed')
|
||||
|
||||
# MOZ_STACKWALKING is defined in configure.in when the build configuration meets
|
||||
# the conditions for GeckoStackWalk to work correctly.
|
||||
# We exclude this file from other build configurations so that if somebody adds a
|
||||
# new usage of NS_StackWalk it will cause a link error, which is better than having
|
||||
# GeckoStackWalk silently return garbage at runtime.
|
||||
if CONFIG['MOZ_STACKWALKING']:
|
||||
SOURCES += [
|
||||
'StackWalk.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#ifdef MOZ_STACKWALKING
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#endif
|
||||
|
||||
#define TARGET_SANDBOX_EXPORT __declspec(dllexport)
|
||||
@@ -63,10 +63,10 @@ StackFrameToOStringStream(uint32_t aFrameNumber, void* aPC, void* aSP,
|
||||
void* aClosure)
|
||||
{
|
||||
std::ostringstream* stream = static_cast<std::ostringstream*>(aClosure);
|
||||
nsCodeAddressDetails details;
|
||||
MozCodeAddressDetails details;
|
||||
char buf[1024];
|
||||
NS_DescribeCodeAddress(aPC, &details);
|
||||
NS_FormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
|
||||
MozDescribeCodeAddress(aPC, &details);
|
||||
MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
|
||||
*stream << std::endl << "--" << buf;
|
||||
stream->flush();
|
||||
}
|
||||
@@ -90,7 +90,7 @@ Log(const char* aMessageType,
|
||||
if (aShouldLogStackTrace) {
|
||||
if (sStackTraceDepth) {
|
||||
msgStream << std::endl << "Stack Trace:";
|
||||
NS_StackWalk(StackFrameToOStringStream, aFramesToSkip, sStackTraceDepth,
|
||||
MozStackWalk(StackFrameToOStringStream, aFramesToSkip, sStackTraceDepth,
|
||||
&msgStream, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
@@ -74,10 +74,10 @@ static void SandboxPrintStackFrame(uint32_t aFrameNumber, void *aPC, void *aSP,
|
||||
void *aClosure)
|
||||
{
|
||||
char buf[1024];
|
||||
nsCodeAddressDetails details;
|
||||
MozCodeAddressDetails details;
|
||||
|
||||
NS_DescribeCodeAddress(aPC, &details);
|
||||
NS_FormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
|
||||
MozDescribeCodeAddress(aPC, &details);
|
||||
MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
|
||||
SANDBOX_LOG_ERROR("frame %s", buf);
|
||||
}
|
||||
|
||||
@@ -87,11 +87,11 @@ SandboxLogCStack()
|
||||
// Skip 3 frames: one for this module, one for the signal handler in
|
||||
// libmozsandbox, and one for the signal trampoline.
|
||||
//
|
||||
// Warning: this might not print any stack frames. NS_StackWalk
|
||||
// Warning: this might not print any stack frames. MozStackWalk
|
||||
// can't walk past the signal trampoline on ARM (bug 968531), and
|
||||
// x86 frame pointer walking may or may not work (bug 1082276).
|
||||
|
||||
NS_StackWalk(SandboxPrintStackFrame, /* skip */ 3, /* max */ 0,
|
||||
MozStackWalk(SandboxPrintStackFrame, /* skip */ 3, /* max */ 0,
|
||||
nullptr, 0, nullptr);
|
||||
SANDBOX_LOG_ERROR("end of stack.");
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ unsigned int _gdb_sleep_duration = 300;
|
||||
|
||||
#include <unistd.h>
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
|
||||
// NB: keep me up to date with the same variable in
|
||||
// ipc/chromium/chrome/common/ipc_channel_posix.cc
|
||||
@@ -70,10 +70,10 @@ static void PrintStackFrame(uint32_t aFrameNumber, void *aPC, void *aSP,
|
||||
void *aClosure)
|
||||
{
|
||||
char buf[1024];
|
||||
nsCodeAddressDetails details;
|
||||
MozCodeAddressDetails details;
|
||||
|
||||
NS_DescribeCodeAddress(aPC, &details);
|
||||
NS_FormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
|
||||
MozDescribeCodeAddress(aPC, &details);
|
||||
MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
|
||||
fprintf(stdout, "%s\n", buf);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ ah_crap_handler(int signum)
|
||||
signum);
|
||||
|
||||
printf("Stack:\n");
|
||||
NS_StackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0,
|
||||
MozStackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0,
|
||||
nullptr, 0, nullptr);
|
||||
|
||||
printf("Sleeping for %d seconds.\n",_gdb_sleep_duration);
|
||||
|
||||
@@ -38,6 +38,7 @@ bool mozilla_sampler_is_active();
|
||||
void mozilla_sampler_responsiveness(TimeStamp time);
|
||||
void mozilla_sampler_frame_number(int frameNumber);
|
||||
const double* mozilla_sampler_get_responsiveness();
|
||||
|
||||
void mozilla_sampler_save();
|
||||
|
||||
mozilla::UniquePtr<char[]> mozilla_sampler_get_profile(float aSinceTime);
|
||||
@@ -46,6 +47,12 @@ JSObject *mozilla_sampler_get_profile_data(JSContext *aCx, float aSinceTime);
|
||||
void mozilla_sampler_get_profile_data_async(float aSinceTime,
|
||||
mozilla::dom::Promise* aPromise);
|
||||
|
||||
// Make this function easily callable from a debugger in a build without
|
||||
// debugging information (work around http://llvm.org/bugs/show_bug.cgi?id=22211)
|
||||
extern "C" {
|
||||
void mozilla_sampler_save_profile_to_file(const char* aFilename);
|
||||
}
|
||||
|
||||
const char** mozilla_sampler_get_features();
|
||||
|
||||
void mozilla_sampler_get_buffer_info(uint32_t *aCurrentPosition, uint32_t *aTotalSize,
|
||||
|
||||
@@ -111,11 +111,21 @@ ProfileBuffer::ProfileBuffer(int aEntrySize)
|
||||
{
|
||||
}
|
||||
|
||||
ProfileBuffer::~ProfileBuffer()
|
||||
{
|
||||
while (mStoredMarkers.peek()) {
|
||||
delete mStoredMarkers.popHead();
|
||||
}
|
||||
}
|
||||
|
||||
// Called from signal, call only reentrant functions
|
||||
void ProfileBuffer::addTag(const ProfileEntry& aTag)
|
||||
{
|
||||
mEntries[mWritePos++] = aTag;
|
||||
if (mWritePos == mEntrySize) {
|
||||
// Wrapping around may result in things referenced in the buffer (e.g.,
|
||||
// JIT code addresses and markers) being incorrectly collected.
|
||||
MOZ_ASSERT(mGeneration != UINT32_MAX);
|
||||
mGeneration++;
|
||||
mWritePos = 0;
|
||||
}
|
||||
@@ -134,7 +144,7 @@ void ProfileBuffer::addStoredMarker(ProfilerMarker *aStoredMarker) {
|
||||
void ProfileBuffer::deleteExpiredStoredMarkers() {
|
||||
// Delete markers of samples that have been overwritten due to circular
|
||||
// buffer wraparound.
|
||||
int generation = mGeneration;
|
||||
uint32_t generation = mGeneration;
|
||||
while (mStoredMarkers.peek() &&
|
||||
mStoredMarkers.peek()->HasExpired(generation)) {
|
||||
delete mStoredMarkers.popHead();
|
||||
|
||||
@@ -250,7 +250,7 @@ protected:
|
||||
char* processDynamicTag(int readPos, int* tagsConsumed, char* tagBuff);
|
||||
int FindLastSampleOfThread(int aThreadId);
|
||||
|
||||
~ProfileBuffer() {}
|
||||
~ProfileBuffer();
|
||||
|
||||
public:
|
||||
// Circular buffer 'Keep One Slot Open' implementation for simplicity
|
||||
@@ -267,7 +267,7 @@ public:
|
||||
int mEntrySize;
|
||||
|
||||
// How many times mWritePos has wrapped around.
|
||||
int mGeneration;
|
||||
uint32_t mGeneration;
|
||||
|
||||
// Markers that marker entries in the buffer might refer to.
|
||||
ProfilerMarkerLinkedList mStoredMarkers;
|
||||
@@ -410,7 +410,6 @@ public:
|
||||
}
|
||||
|
||||
uint32_t bufferGeneration() const {
|
||||
MOZ_ASSERT(mBuffer->mGeneration >= 0);
|
||||
return mBuffer->mGeneration;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,9 +92,9 @@ public:
|
||||
|
||||
void StreamJSON(SpliceableJSONWriter& aWriter, UniqueStacks& aUniqueStacks) const;
|
||||
|
||||
void SetGeneration(int aGenID);
|
||||
void SetGeneration(uint32_t aGenID);
|
||||
|
||||
bool HasExpired(int aGenID) const {
|
||||
bool HasExpired(uint32_t aGenID) const {
|
||||
return mGenID + 2 <= aGenID;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ private:
|
||||
ProfilerMarkerPayload* mPayload;
|
||||
ProfilerMarker* mNext;
|
||||
float mTime;
|
||||
int mGenID;
|
||||
uint32_t mGenID;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -47,9 +47,6 @@
|
||||
#if defined(MOZ_PROFILING) && (defined(XP_MACOSX) || defined(XP_WIN))
|
||||
#define USE_NS_STACKWALK
|
||||
#endif
|
||||
#ifdef USE_NS_STACKWALK
|
||||
#include "nsStackWalk.h"
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
typedef CONTEXT tickcontext_t;
|
||||
@@ -635,7 +632,16 @@ void mergeStacksIntoProfile(ThreadProfile& aProfile, TickSample* aSample, Native
|
||||
// like the native stack, the JS stack is iterated youngest-to-oldest and we
|
||||
// need to iterate oldest-to-youngest when adding entries to aProfile.
|
||||
|
||||
uint32_t startBufferGen = aProfile.bufferGeneration();
|
||||
// Synchronous sampling reports an invalid buffer generation to
|
||||
// ProfilingFrameIterator to avoid incorrectly resetting the generation of
|
||||
// sampled JIT entries inside the JS engine. See note below concerning 'J'
|
||||
// entries.
|
||||
uint32_t startBufferGen;
|
||||
if (aSample->isSamplingCurrentThread) {
|
||||
startBufferGen = UINT32_MAX;
|
||||
} else {
|
||||
startBufferGen = aProfile.bufferGeneration();
|
||||
}
|
||||
uint32_t jsCount = 0;
|
||||
JS::ProfilingFrameIterator::Frame jsFrames[1000];
|
||||
// Only walk jit stack if profiling frame iterator is turned on.
|
||||
@@ -781,14 +787,13 @@ void mergeStacksIntoProfile(ThreadProfile& aProfile, TickSample* aSample, Native
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aProfile.bufferGeneration() >= startBufferGen);
|
||||
uint32_t lapCount = aProfile.bufferGeneration() - startBufferGen;
|
||||
|
||||
// Update the JS runtime with the current profile sample buffer generation.
|
||||
//
|
||||
// Do not do this for synchronous sampling, which create their own
|
||||
// ProfileBuffers.
|
||||
if (!aSample->isSamplingCurrentThread && pseudoStack->mRuntime) {
|
||||
MOZ_ASSERT(aProfile.bufferGeneration() >= startBufferGen);
|
||||
uint32_t lapCount = aProfile.bufferGeneration() - startBufferGen;
|
||||
JS::UpdateJSRuntimeProfilerSampleBufferGen(pseudoStack->mRuntime,
|
||||
aProfile.bufferGeneration(),
|
||||
lapCount);
|
||||
@@ -823,7 +828,7 @@ void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample
|
||||
};
|
||||
|
||||
// Start with the current function. We use 0 as the frame number here because
|
||||
// the FramePointerStackWalk() and NS_StackWalk() calls below will use 1..N.
|
||||
// the FramePointerStackWalk() and MozStackWalk() calls below will use 1..N.
|
||||
// This is a bit weird but it doesn't matter because StackWalkCallback()
|
||||
// doesn't use the frame number argument.
|
||||
StackWalkCallback(/* frameNumber */ 0, aSample->pc, aSample->sp, &nativeStack);
|
||||
@@ -834,7 +839,7 @@ void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample
|
||||
void *stackEnd = reinterpret_cast<void*>(-1);
|
||||
if (pt)
|
||||
stackEnd = static_cast<char*>(pthread_get_stackaddr_np(pt));
|
||||
nsresult rv = NS_OK;
|
||||
bool rv = true;
|
||||
if (aSample->fp >= aSample->sp && aSample->fp <= stackEnd)
|
||||
rv = FramePointerStackWalk(StackWalkCallback, /* skipFrames */ 0,
|
||||
maxFrames, &nativeStack,
|
||||
@@ -843,17 +848,17 @@ void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample
|
||||
void *platformData = nullptr;
|
||||
#ifdef XP_WIN
|
||||
if (aSample->isSamplingCurrentThread) {
|
||||
// In this case we want NS_StackWalk to know that it's walking the
|
||||
// In this case we want MozStackWalk to know that it's walking the
|
||||
// current thread's stack, so we pass 0 as the thread handle.
|
||||
thread = 0;
|
||||
}
|
||||
platformData = aSample->context;
|
||||
#endif // XP_WIN
|
||||
|
||||
nsresult rv = NS_StackWalk(StackWalkCallback, /* skipFrames */ 0, maxFrames,
|
||||
bool rv = MozStackWalk(StackWalkCallback, /* skipFrames */ 0, maxFrames,
|
||||
&nativeStack, thread, platformData);
|
||||
#endif
|
||||
if (NS_SUCCEEDED(rv))
|
||||
if (rv)
|
||||
mergeStacksIntoProfile(aProfile, aSample, nativeStack);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -197,7 +197,7 @@ ProfilerMarker::~ProfilerMarker() {
|
||||
}
|
||||
|
||||
void
|
||||
ProfilerMarker::SetGeneration(int aGenID) {
|
||||
ProfilerMarker::SetGeneration(uint32_t aGenID) {
|
||||
mGenID = aGenID;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Types.h"
|
||||
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace mozilla {
|
||||
// while |free| is used to free strings created by |copy|.
|
||||
//
|
||||
// |DescribeCodeAddressLock| is needed when the callers may be holding a lock
|
||||
// used by NS_DescribeCodeAddress. |DescribeCodeAddressLock| must implement
|
||||
// used by MozDescribeCodeAddress. |DescribeCodeAddressLock| must implement
|
||||
// static methods IsLocked(), Unlock() and Lock().
|
||||
template <class StringTable,
|
||||
class StringAlloc,
|
||||
@@ -35,9 +35,9 @@ template <class StringTable,
|
||||
class CodeAddressService
|
||||
{
|
||||
// GetLocation() is the key function in this class. It's basically a wrapper
|
||||
// around NS_DescribeCodeAddress.
|
||||
// around MozDescribeCodeAddress.
|
||||
//
|
||||
// However, NS_DescribeCodeAddress is very slow on some platforms, and we
|
||||
// However, MozDescribeCodeAddress is very slow on some platforms, and we
|
||||
// have lots of repeated (i.e. same PC) calls to it. So we do some caching
|
||||
// of results. Each cached result includes two strings (|mFunction| and
|
||||
// |mLibrary|), so we also optimize them for space in the following ways.
|
||||
@@ -137,15 +137,15 @@ public:
|
||||
if (!entry.mInUse || entry.mPc != aPc) {
|
||||
mNumCacheMisses++;
|
||||
|
||||
// NS_DescribeCodeAddress can (on Linux) acquire a lock inside
|
||||
// MozDescribeCodeAddress can (on Linux) acquire a lock inside
|
||||
// the shared library loader. Another thread might call malloc
|
||||
// while holding that lock (when loading a shared library). So
|
||||
// we have to exit the lock around this call. For details, see
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=363334#c3
|
||||
nsCodeAddressDetails details;
|
||||
MozCodeAddressDetails details;
|
||||
{
|
||||
DescribeCodeAddressLock::Unlock();
|
||||
(void)NS_DescribeCodeAddress(const_cast<void*>(aPc), &details);
|
||||
(void)MozDescribeCodeAddress(const_cast<void*>(aPc), &details);
|
||||
DescribeCodeAddressLock::Lock();
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ public:
|
||||
|
||||
MOZ_ASSERT(entry.mPc == aPc);
|
||||
|
||||
NS_FormatCodeAddress(aBuf, aBufLen, aFrameNumber, entry.mPc,
|
||||
MozFormatCodeAddress(aBuf, aBufLen, aFrameNumber, entry.mPc,
|
||||
entry.mFunction, entry.mLibrary, entry.mLOffset,
|
||||
entry.mFileName, entry.mLineNo);
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
/* API for getting a stack trace of the C/C++ */
|
||||
|
||||
#ifndef StackWalk_h_
|
||||
#define StackWalk_h_
|
||||
|
||||
// XXX: it would be nice to eventually remove this header dependency on nsStackWalk.h
|
||||
#include "nsStackWalk.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsresult
|
||||
FramePointerStackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||
uint32_t aMaxFrames, void* aClosure, void** aBp,
|
||||
void* aStackEnd);
|
||||
|
||||
}
|
||||
|
||||
#endif /* !defined(StackWalk_h_) */
|
||||
@@ -57,7 +57,6 @@ EXPORTS += [
|
||||
'nsISupportsBase.h',
|
||||
'nsObjCExceptions.h',
|
||||
'nsQueryObject.h',
|
||||
'nsStackWalk.h',
|
||||
'nsTraceRefcnt.h',
|
||||
'nsWeakPtr.h',
|
||||
]
|
||||
@@ -79,7 +78,6 @@ EXPORTS.mozilla += [
|
||||
'HoldDropJSObjects.h',
|
||||
'LinuxUtils.h',
|
||||
'nsMemoryInfoDumper.h',
|
||||
'StackWalk.h',
|
||||
'StaticMutex.h',
|
||||
'StaticPtr.h',
|
||||
'SystemMemoryReporter.h',
|
||||
@@ -120,16 +118,6 @@ UNIFIED_SOURCES += [
|
||||
'nsVersionComparatorImpl.cpp',
|
||||
]
|
||||
|
||||
# MOZ_STACKWALKING is defined in configure.in when the build configuration meets
|
||||
# the conditions for NS_StackWalk to work correctly.
|
||||
# We exclude this file from other build configurations so that if somebody adds a
|
||||
# new usage of NS_StackWalk it will cause a link error, which is better than having
|
||||
# NS_StackWalk silently return garbage at runtime.
|
||||
if CONFIG['MOZ_STACKWALKING']:
|
||||
SOURCES += [
|
||||
'nsStackWalk.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'Linux':
|
||||
SOURCES += [
|
||||
'LinuxUtils.cpp',
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
/**
|
||||
* Initialize the critical sections for this platform so that we can
|
||||
* abort stack walks when needed.
|
||||
*/
|
||||
void
|
||||
StackWalkInitCriticalAddress(void);
|
||||
@@ -18,8 +18,7 @@
|
||||
#include "nsCRT.h"
|
||||
#include <math.h>
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsStackWalkPrivate.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "CodeAddressService.h"
|
||||
@@ -210,7 +209,7 @@ struct CodeAddressServiceStringAlloc final
|
||||
static void free(char* aPtr) { ::free(aPtr); }
|
||||
};
|
||||
|
||||
// WalkTheStack does not hold any locks needed by NS_DescribeCodeAddress, so
|
||||
// WalkTheStack does not hold any locks needed by MozDescribeCodeAddress, so
|
||||
// this class does not need to do anything.
|
||||
struct CodeAddressServiceLock final
|
||||
{
|
||||
@@ -829,11 +828,11 @@ static void
|
||||
PrintStackFrame(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
|
||||
{
|
||||
FILE* stream = (FILE*)aClosure;
|
||||
nsCodeAddressDetails details;
|
||||
MozCodeAddressDetails details;
|
||||
char buf[1024];
|
||||
|
||||
NS_DescribeCodeAddress(aPC, &details);
|
||||
NS_FormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
|
||||
MozDescribeCodeAddress(aPC, &details);
|
||||
MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
|
||||
fprintf(stream, "%s\n", buf);
|
||||
fflush(stream);
|
||||
}
|
||||
@@ -857,7 +856,7 @@ void
|
||||
nsTraceRefcnt::WalkTheStack(FILE* aStream)
|
||||
{
|
||||
#ifdef MOZ_STACKWALKING
|
||||
NS_StackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0, aStream,
|
||||
MozStackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0, aStream,
|
||||
0, nullptr);
|
||||
#endif
|
||||
}
|
||||
@@ -869,7 +868,7 @@ nsTraceRefcnt::WalkTheStackCached(FILE* aStream)
|
||||
if (!gCodeAddressService) {
|
||||
gCodeAddressService = new WalkTheStackCodeAddressService();
|
||||
}
|
||||
NS_StackWalk(PrintStackFrameCached, /* skipFrames */ 2, /* maxFrames */ 0,
|
||||
MozStackWalk(PrintStackFrameCached, /* skipFrames */ 2, /* maxFrames */ 0,
|
||||
aStream, 0, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#include "plstr.h"
|
||||
#include "prio.h"
|
||||
|
||||
@@ -128,7 +128,7 @@ LateWriteObserver::Observe(IOInterposeObserver::Observation& aOb)
|
||||
// concurrently from many writes, so we use multiple temporary files.
|
||||
std::vector<uintptr_t> rawStack;
|
||||
|
||||
NS_StackWalk(RecordStackWalker, /* skipFrames */ 0, /* maxFrames */ 0,
|
||||
MozStackWalk(RecordStackWalker, /* skipFrames */ 0, /* maxFrames */ 0,
|
||||
reinterpret_cast<void*>(&rawStack), 0, nullptr);
|
||||
|
||||
nsPrintfCString nameAux("%s%s%s", mProfileDirectory,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "mozilla/ProcessedStack.h"
|
||||
#include "mozilla/Scoped.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
#include "plstr.h"
|
||||
#include "prio.h"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#ifndef MOZ_CALLSTACK_DISABLED
|
||||
#include "CodeAddressService.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#include "nsTHashtable.h"
|
||||
#endif
|
||||
|
||||
@@ -68,7 +68,7 @@ BlockingResourceBase::GetStackTrace(AcquisitionState& aState)
|
||||
|
||||
// NB: Ignore the return value, there's nothing useful we can do if this
|
||||
// this fails.
|
||||
NS_StackWalk(StackWalkCallback, kSkipFrames, 24, &aState, 0, nullptr);
|
||||
MozStackWalk(StackWalkCallback, kSkipFrames, 24, &aState, 0, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
#if defined(NS_FUNCTION_TIMER) && defined(_MSC_VER)
|
||||
#include "nsTimerImpl.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#endif
|
||||
#ifdef NS_FUNCTION_TIMER
|
||||
#include "nsCRT.h"
|
||||
|
||||
Reference in New Issue
Block a user