mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-09 09:18:42 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
|
|
@ -0,0 +1,100 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
// Test that the `JS::ubi::Node`s we create from
|
||||
// `mozilla::devtools::DeserializedNode` instances look and behave as we would
|
||||
// like.
|
||||
|
||||
#include "DevTools.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/devtools/DeserializedNode.h"
|
||||
|
||||
using testing::Field;
|
||||
using testing::ReturnRef;
|
||||
|
||||
// A mock DeserializedNode for testing.
|
||||
struct MockDeserializedNode : public DeserializedNode
|
||||
{
|
||||
MockDeserializedNode(NodeId id, const char16_t* typeName, uint64_t size)
|
||||
: DeserializedNode(id, typeName, size)
|
||||
{ }
|
||||
|
||||
bool addEdge(DeserializedEdge&& edge)
|
||||
{
|
||||
return edges.append(Move(edge));
|
||||
}
|
||||
|
||||
MOCK_METHOD1(getEdgeReferent, JS::ubi::Node(const DeserializedEdge&));
|
||||
};
|
||||
|
||||
size_t fakeMallocSizeOf(const void*) {
|
||||
EXPECT_TRUE(false);
|
||||
MOZ_ASSERT_UNREACHABLE("fakeMallocSizeOf should never be called because "
|
||||
"DeserializedNodes report the deserialized size.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEF_TEST(DeserializedNodeUbiNodes, {
|
||||
const char16_t* typeName = u"TestTypeName";
|
||||
const char* className = "MyObjectClassName";
|
||||
const char* filename = "my-cool-filename.js";
|
||||
|
||||
NodeId id = uint64_t(1) << 33;
|
||||
uint64_t size = uint64_t(1) << 60;
|
||||
MockDeserializedNode mocked(id, typeName, size);
|
||||
mocked.coarseType = JS::ubi::CoarseType::Script;
|
||||
mocked.jsObjectClassName = className;
|
||||
mocked.scriptFilename = filename;
|
||||
|
||||
DeserializedNode& deserialized = mocked;
|
||||
JS::ubi::Node ubi(&deserialized);
|
||||
|
||||
// Test the ubi::Node accessors.
|
||||
|
||||
EXPECT_EQ(size, ubi.size(fakeMallocSizeOf));
|
||||
EXPECT_EQ(typeName, ubi.typeName());
|
||||
EXPECT_EQ(JS::ubi::CoarseType::Script, ubi.coarseType());
|
||||
EXPECT_EQ(id, ubi.identifier());
|
||||
EXPECT_FALSE(ubi.isLive());
|
||||
EXPECT_EQ(ubi.jsObjectClassName(), className);
|
||||
EXPECT_EQ(ubi.scriptFilename(), filename);
|
||||
|
||||
// Test the ubi::Node's edges.
|
||||
|
||||
UniquePtr<DeserializedNode> referent1(new MockDeserializedNode(1,
|
||||
nullptr,
|
||||
10));
|
||||
DeserializedEdge edge1(referent1->id);
|
||||
mocked.addEdge(Move(edge1));
|
||||
EXPECT_CALL(mocked, getEdgeReferent(EdgeTo(referent1->id)))
|
||||
.Times(1)
|
||||
.WillOnce(Return(JS::ubi::Node(referent1.get())));
|
||||
|
||||
UniquePtr<DeserializedNode> referent2(new MockDeserializedNode(2,
|
||||
nullptr,
|
||||
20));
|
||||
DeserializedEdge edge2(referent2->id);
|
||||
mocked.addEdge(Move(edge2));
|
||||
EXPECT_CALL(mocked, getEdgeReferent(EdgeTo(referent2->id)))
|
||||
.Times(1)
|
||||
.WillOnce(Return(JS::ubi::Node(referent2.get())));
|
||||
|
||||
UniquePtr<DeserializedNode> referent3(new MockDeserializedNode(3,
|
||||
nullptr,
|
||||
30));
|
||||
DeserializedEdge edge3(referent3->id);
|
||||
mocked.addEdge(Move(edge3));
|
||||
EXPECT_CALL(mocked, getEdgeReferent(EdgeTo(referent3->id)))
|
||||
.Times(1)
|
||||
.WillOnce(Return(JS::ubi::Node(referent3.get())));
|
||||
|
||||
auto range = ubi.edges(cx);
|
||||
ASSERT_TRUE(!!range);
|
||||
|
||||
for ( ; !range->empty(); range->popFront()) {
|
||||
// Nothing to do here. This loop ensures that we get each edge referent
|
||||
// that we expect above.
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
// Test that the `JS::ubi::StackFrame`s we create from
|
||||
// `mozilla::devtools::DeserializedStackFrame` instances look and behave as we would
|
||||
// like.
|
||||
|
||||
#include "DevTools.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/devtools/DeserializedNode.h"
|
||||
|
||||
using testing::Field;
|
||||
using testing::ReturnRef;
|
||||
|
||||
// A mock DeserializedStackFrame for testing.
|
||||
struct MockDeserializedStackFrame : public DeserializedStackFrame
|
||||
{
|
||||
MockDeserializedStackFrame() : DeserializedStackFrame() { }
|
||||
};
|
||||
|
||||
DEF_TEST(DeserializedStackFrameUbiStackFrames, {
|
||||
StackFrameId id = uint64_t(1) << 42;
|
||||
uint32_t line = 1337;
|
||||
uint32_t column = 9; // 3 space tabs!?
|
||||
const char16_t* source = u"my-javascript-file.js";
|
||||
const char16_t* functionDisplayName = u"myFunctionName";
|
||||
|
||||
MockDeserializedStackFrame mocked;
|
||||
mocked.id = id;
|
||||
mocked.line = line;
|
||||
mocked.column = column;
|
||||
mocked.source = source;
|
||||
mocked.functionDisplayName = functionDisplayName;
|
||||
|
||||
DeserializedStackFrame& deserialized = mocked;
|
||||
JS::ubi::StackFrame ubiFrame(&deserialized);
|
||||
|
||||
// Test the JS::ubi::StackFrame accessors.
|
||||
|
||||
EXPECT_EQ(id, ubiFrame.identifier());
|
||||
EXPECT_EQ(JS::ubi::StackFrame(), ubiFrame.parent());
|
||||
EXPECT_EQ(line, ubiFrame.line());
|
||||
EXPECT_EQ(column, ubiFrame.column());
|
||||
EXPECT_EQ(JS::ubi::AtomOrTwoByteChars(source), ubiFrame.source());
|
||||
EXPECT_EQ(JS::ubi::AtomOrTwoByteChars(functionDisplayName),
|
||||
ubiFrame.functionDisplayName());
|
||||
EXPECT_FALSE(ubiFrame.isSelfHosted(cx));
|
||||
EXPECT_FALSE(ubiFrame.isSystem());
|
||||
|
||||
JS::RootedObject savedFrame(cx);
|
||||
EXPECT_TRUE(ubiFrame.constructSavedFrameStack(cx, &savedFrame));
|
||||
|
||||
uint32_t frameLine;
|
||||
ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameLine(cx, savedFrame, &frameLine));
|
||||
EXPECT_EQ(line, frameLine);
|
||||
|
||||
uint32_t frameColumn;
|
||||
ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameColumn(cx, savedFrame, &frameColumn));
|
||||
EXPECT_EQ(column, frameColumn);
|
||||
|
||||
JS::RootedObject parent(cx);
|
||||
ASSERT_EQ(JS::SavedFrameResult::Ok, JS::GetSavedFrameParent(cx, savedFrame, &parent));
|
||||
EXPECT_EQ(nullptr, parent);
|
||||
|
||||
ASSERT_EQ(NS_strlen(source), 21U);
|
||||
char16_t sourceBuf[21] = {};
|
||||
|
||||
// Test when the length is shorter than the string length.
|
||||
auto written = ubiFrame.source(RangedPtr<char16_t>(sourceBuf), 3);
|
||||
EXPECT_EQ(written, 3U);
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
EXPECT_EQ(sourceBuf[i], source[i]);
|
||||
}
|
||||
|
||||
written = ubiFrame.source(RangedPtr<char16_t>(sourceBuf), 21);
|
||||
EXPECT_EQ(written, 21U);
|
||||
for (size_t i = 0; i < 21; i++) {
|
||||
EXPECT_EQ(sourceBuf[i], source[i]);
|
||||
}
|
||||
|
||||
ASSERT_EQ(NS_strlen(functionDisplayName), 14U);
|
||||
char16_t nameBuf[14] = {};
|
||||
|
||||
written = ubiFrame.functionDisplayName(RangedPtr<char16_t>(nameBuf), 14);
|
||||
EXPECT_EQ(written, 14U);
|
||||
for (size_t i = 0; i < 14; i++) {
|
||||
EXPECT_EQ(nameBuf[i], functionDisplayName[i]);
|
||||
}
|
||||
});
|
||||
276
devtools/shared/heapsnapshot/tests/gtest/DevTools.h
Normal file
276
devtools/shared/heapsnapshot/tests/gtest/DevTools.h
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_devtools_gtest_DevTools__
|
||||
#define mozilla_devtools_gtest_DevTools__
|
||||
|
||||
#include "CoreDump.pb.h"
|
||||
#include "jsapi.h"
|
||||
#include "jspubtd.h"
|
||||
#include "nsCRTGlue.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "mozilla/devtools/HeapSnapshot.h"
|
||||
#include "mozilla/dom/ChromeUtils.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "js/Principals.h"
|
||||
#include "js/UbiNode.h"
|
||||
#include "js/UniquePtr.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::devtools;
|
||||
using namespace mozilla::dom;
|
||||
using namespace testing;
|
||||
|
||||
// GTest fixture class that all of our tests derive from.
|
||||
struct DevTools : public ::testing::Test {
|
||||
bool _initialized;
|
||||
JSContext* cx;
|
||||
JSCompartment* compartment;
|
||||
JS::Zone* zone;
|
||||
JS::PersistentRootedObject global;
|
||||
|
||||
DevTools()
|
||||
: _initialized(false),
|
||||
cx(nullptr)
|
||||
{ }
|
||||
|
||||
virtual void SetUp() {
|
||||
MOZ_ASSERT(!_initialized);
|
||||
|
||||
cx = getContext();
|
||||
if (!cx)
|
||||
return;
|
||||
|
||||
JS_BeginRequest(cx);
|
||||
|
||||
global.init(cx, createGlobal());
|
||||
if (!global)
|
||||
return;
|
||||
JS_EnterCompartment(cx, global);
|
||||
|
||||
compartment = js::GetContextCompartment(cx);
|
||||
zone = js::GetContextZone(cx);
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
JSContext* getContext() {
|
||||
return CycleCollectedJSContext::Get()->Context();
|
||||
}
|
||||
|
||||
static void reportError(JSContext* cx, const char* message, JSErrorReport* report) {
|
||||
fprintf(stderr, "%s:%u:%s\n",
|
||||
report->filename ? report->filename : "<no filename>",
|
||||
(unsigned int) report->lineno,
|
||||
message);
|
||||
}
|
||||
|
||||
static const JSClass* getGlobalClass() {
|
||||
static const JSClassOps globalClassOps = {
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr,
|
||||
JS_GlobalObjectTraceHook
|
||||
};
|
||||
static const JSClass globalClass = {
|
||||
"global", JSCLASS_GLOBAL_FLAGS,
|
||||
&globalClassOps
|
||||
};
|
||||
return &globalClass;
|
||||
}
|
||||
|
||||
JSObject* createGlobal()
|
||||
{
|
||||
/* Create the global object. */
|
||||
JS::RootedObject newGlobal(cx);
|
||||
JS::CompartmentOptions options;
|
||||
options.behaviors().setVersion(JSVERSION_LATEST);
|
||||
newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
|
||||
JS::FireOnNewGlobalHook, options);
|
||||
if (!newGlobal)
|
||||
return nullptr;
|
||||
|
||||
JSAutoCompartment ac(cx, newGlobal);
|
||||
|
||||
/* Populate the global object with the standard globals, like Object and
|
||||
Array. */
|
||||
if (!JS_InitStandardClasses(cx, newGlobal))
|
||||
return nullptr;
|
||||
|
||||
return newGlobal;
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
_initialized = false;
|
||||
|
||||
if (global) {
|
||||
JS_LeaveCompartment(cx, nullptr);
|
||||
global = nullptr;
|
||||
}
|
||||
if (cx)
|
||||
JS_EndRequest(cx);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Helper to define a test and ensure that the fixture is initialized properly.
|
||||
#define DEF_TEST(name, body) \
|
||||
TEST_F(DevTools, name) { \
|
||||
ASSERT_TRUE(_initialized); \
|
||||
body \
|
||||
}
|
||||
|
||||
|
||||
// Fake JS::ubi::Node implementation
|
||||
class MOZ_STACK_CLASS FakeNode
|
||||
{
|
||||
public:
|
||||
JS::ubi::EdgeVector edges;
|
||||
JSCompartment* compartment;
|
||||
JS::Zone* zone;
|
||||
size_t size;
|
||||
|
||||
explicit FakeNode()
|
||||
: edges(),
|
||||
compartment(nullptr),
|
||||
zone(nullptr),
|
||||
size(1)
|
||||
{ }
|
||||
};
|
||||
|
||||
namespace JS {
|
||||
namespace ubi {
|
||||
|
||||
template<>
|
||||
class Concrete<FakeNode> : public Base
|
||||
{
|
||||
const char16_t* typeName() const override {
|
||||
return concreteTypeName;
|
||||
}
|
||||
|
||||
js::UniquePtr<EdgeRange> edges(JSContext*, bool) const override {
|
||||
return js::UniquePtr<EdgeRange>(js_new<PreComputedEdgeRange>(get().edges));
|
||||
}
|
||||
|
||||
Size size(mozilla::MallocSizeOf) const override {
|
||||
return get().size;
|
||||
}
|
||||
|
||||
JS::Zone* zone() const override {
|
||||
return get().zone;
|
||||
}
|
||||
|
||||
JSCompartment* compartment() const override {
|
||||
return get().compartment;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit Concrete(FakeNode* ptr) : Base(ptr) { }
|
||||
FakeNode& get() const { return *static_cast<FakeNode*>(ptr); }
|
||||
|
||||
public:
|
||||
static const char16_t concreteTypeName[];
|
||||
static void construct(void* storage, FakeNode* ptr) {
|
||||
new (storage) Concrete(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
const char16_t Concrete<FakeNode>::concreteTypeName[] = u"FakeNode";
|
||||
|
||||
} // namespace ubi
|
||||
} // namespace JS
|
||||
|
||||
void AddEdge(FakeNode& node, FakeNode& referent, const char16_t* edgeName = nullptr) {
|
||||
char16_t* ownedEdgeName = nullptr;
|
||||
if (edgeName) {
|
||||
ownedEdgeName = NS_strdup(edgeName);
|
||||
ASSERT_NE(ownedEdgeName, nullptr);
|
||||
}
|
||||
|
||||
JS::ubi::Edge edge(ownedEdgeName, &referent);
|
||||
ASSERT_TRUE(node.edges.append(mozilla::Move(edge)));
|
||||
}
|
||||
|
||||
|
||||
// Custom GMock Matchers
|
||||
|
||||
// Use the testing namespace to avoid static analysis failures in the gmock
|
||||
// matcher classes that get generated from MATCHER_P macros.
|
||||
namespace testing {
|
||||
|
||||
// Ensure that given node has the expected number of edges.
|
||||
MATCHER_P2(EdgesLength, cx, expectedLength, "") {
|
||||
auto edges = arg.edges(cx);
|
||||
if (!edges)
|
||||
return false;
|
||||
|
||||
int actualLength = 0;
|
||||
for ( ; !edges->empty(); edges->popFront())
|
||||
actualLength++;
|
||||
|
||||
return Matcher<int>(Eq(expectedLength))
|
||||
.MatchAndExplain(actualLength, result_listener);
|
||||
}
|
||||
|
||||
// Get the nth edge and match it with the given matcher.
|
||||
MATCHER_P3(Edge, cx, n, matcher, "") {
|
||||
auto edges = arg.edges(cx);
|
||||
if (!edges)
|
||||
return false;
|
||||
|
||||
int i = 0;
|
||||
for ( ; !edges->empty(); edges->popFront()) {
|
||||
if (i == n) {
|
||||
return Matcher<const JS::ubi::Edge&>(matcher)
|
||||
.MatchAndExplain(edges->front(), result_listener);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensures that two char16_t* strings are equal.
|
||||
MATCHER_P(UTF16StrEq, str, "") {
|
||||
return NS_strcmp(arg, str) == 0;
|
||||
}
|
||||
|
||||
MATCHER_P(UniqueUTF16StrEq, str, "") {
|
||||
return NS_strcmp(arg.get(), str) == 0;
|
||||
}
|
||||
|
||||
MATCHER(UniqueIsNull, "") {
|
||||
return arg.get() == nullptr;
|
||||
}
|
||||
|
||||
// Matches an edge whose referent is the node with the given id.
|
||||
MATCHER_P(EdgeTo, id, "") {
|
||||
return Matcher<const DeserializedEdge&>(Field(&DeserializedEdge::referent, id))
|
||||
.MatchAndExplain(arg, result_listener);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
|
||||
// A mock `Writer` class to be used with testing `WriteHeapGraph`.
|
||||
class MockWriter : public CoreDumpWriter
|
||||
{
|
||||
public:
|
||||
virtual ~MockWriter() override { }
|
||||
MOCK_METHOD2(writeNode, bool(const JS::ubi::Node&, CoreDumpWriter::EdgePolicy));
|
||||
MOCK_METHOD1(writeMetadata, bool(uint64_t));
|
||||
};
|
||||
|
||||
void ExpectWriteNode(MockWriter& writer, FakeNode& node) {
|
||||
EXPECT_CALL(writer, writeNode(Eq(JS::ubi::Node(&node)), _))
|
||||
.Times(1)
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
#endif // mozilla_devtools_gtest_DevTools__
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
// Test that heap snapshots cross compartment boundaries when expected.
|
||||
|
||||
#include "DevTools.h"
|
||||
|
||||
DEF_TEST(DoesCrossCompartmentBoundaries, {
|
||||
// Create a new global to get a new compartment.
|
||||
JS::CompartmentOptions options;
|
||||
JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx,
|
||||
getGlobalClass(),
|
||||
nullptr,
|
||||
JS::FireOnNewGlobalHook,
|
||||
options));
|
||||
ASSERT_TRUE(newGlobal);
|
||||
JSCompartment* newCompartment = nullptr;
|
||||
{
|
||||
JSAutoCompartment ac(cx, newGlobal);
|
||||
ASSERT_TRUE(JS_InitStandardClasses(cx, newGlobal));
|
||||
newCompartment = js::GetContextCompartment(cx);
|
||||
}
|
||||
ASSERT_TRUE(newCompartment);
|
||||
ASSERT_NE(newCompartment, compartment);
|
||||
|
||||
// Our set of target compartments is both the old and new compartments.
|
||||
JS::CompartmentSet targetCompartments;
|
||||
ASSERT_TRUE(targetCompartments.init());
|
||||
ASSERT_TRUE(targetCompartments.put(compartment));
|
||||
ASSERT_TRUE(targetCompartments.put(newCompartment));
|
||||
|
||||
FakeNode nodeA;
|
||||
FakeNode nodeB;
|
||||
FakeNode nodeC;
|
||||
FakeNode nodeD;
|
||||
|
||||
nodeA.compartment = compartment;
|
||||
nodeB.compartment = nullptr;
|
||||
nodeC.compartment = newCompartment;
|
||||
nodeD.compartment = nullptr;
|
||||
|
||||
AddEdge(nodeA, nodeB);
|
||||
AddEdge(nodeA, nodeC);
|
||||
AddEdge(nodeB, nodeD);
|
||||
|
||||
::testing::NiceMock<MockWriter> writer;
|
||||
|
||||
// Should serialize nodeA, because it is in one of our target compartments.
|
||||
ExpectWriteNode(writer, nodeA);
|
||||
|
||||
// Should serialize nodeB, because it doesn't belong to a compartment and is
|
||||
// therefore assumed to be shared.
|
||||
ExpectWriteNode(writer, nodeB);
|
||||
|
||||
// Should also serialize nodeC, which is in our target compartments, but a
|
||||
// different compartment than A.
|
||||
ExpectWriteNode(writer, nodeC);
|
||||
|
||||
// Should serialize nodeD because it's reachable via B and both nodes B and D
|
||||
// don't belong to a specific compartment.
|
||||
ExpectWriteNode(writer, nodeD);
|
||||
|
||||
JS::AutoCheckCannotGC noGC(cx);
|
||||
|
||||
ASSERT_TRUE(WriteHeapGraph(cx,
|
||||
JS::ubi::Node(&nodeA),
|
||||
writer,
|
||||
/* wantNames = */ false,
|
||||
&targetCompartments,
|
||||
noGC));
|
||||
});
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
// Test that heap snapshots walk the compartment boundaries correctly.
|
||||
|
||||
#include "DevTools.h"
|
||||
|
||||
DEF_TEST(DoesntCrossCompartmentBoundaries, {
|
||||
// Create a new global to get a new compartment.
|
||||
JS::CompartmentOptions options;
|
||||
JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx,
|
||||
getGlobalClass(),
|
||||
nullptr,
|
||||
JS::FireOnNewGlobalHook,
|
||||
options));
|
||||
ASSERT_TRUE(newGlobal);
|
||||
JSCompartment* newCompartment = nullptr;
|
||||
{
|
||||
JSAutoCompartment ac(cx, newGlobal);
|
||||
ASSERT_TRUE(JS_InitStandardClasses(cx, newGlobal));
|
||||
newCompartment = js::GetContextCompartment(cx);
|
||||
}
|
||||
ASSERT_TRUE(newCompartment);
|
||||
ASSERT_NE(newCompartment, compartment);
|
||||
|
||||
// Our set of target compartments is only the pre-existing compartment and
|
||||
// does not include the new compartment.
|
||||
JS::CompartmentSet targetCompartments;
|
||||
ASSERT_TRUE(targetCompartments.init());
|
||||
ASSERT_TRUE(targetCompartments.put(compartment));
|
||||
|
||||
FakeNode nodeA;
|
||||
FakeNode nodeB;
|
||||
FakeNode nodeC;
|
||||
|
||||
nodeA.compartment = compartment;
|
||||
nodeB.compartment = nullptr;
|
||||
nodeC.compartment = newCompartment;
|
||||
|
||||
AddEdge(nodeA, nodeB);
|
||||
AddEdge(nodeB, nodeC);
|
||||
|
||||
::testing::NiceMock<MockWriter> writer;
|
||||
|
||||
// Should serialize nodeA, because it is in our target compartments.
|
||||
ExpectWriteNode(writer, nodeA);
|
||||
|
||||
// Should serialize nodeB, because it doesn't belong to a compartment and is
|
||||
// therefore assumed to be shared.
|
||||
ExpectWriteNode(writer, nodeB);
|
||||
|
||||
// But we shouldn't ever serialize nodeC.
|
||||
|
||||
JS::AutoCheckCannotGC noGC(cx);
|
||||
|
||||
ASSERT_TRUE(WriteHeapGraph(cx,
|
||||
JS::ubi::Node(&nodeA),
|
||||
writer,
|
||||
/* wantNames = */ false,
|
||||
&targetCompartments,
|
||||
noGC));
|
||||
});
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
// Test that edge names get serialized correctly.
|
||||
|
||||
#include "DevTools.h"
|
||||
|
||||
using testing::Field;
|
||||
using testing::IsNull;
|
||||
using testing::Property;
|
||||
using testing::Return;
|
||||
|
||||
DEF_TEST(SerializesEdgeNames, {
|
||||
FakeNode node;
|
||||
FakeNode referent;
|
||||
|
||||
const char16_t edgeName[] = u"edge name";
|
||||
const char16_t emptyStr[] = u"";
|
||||
|
||||
AddEdge(node, referent, edgeName);
|
||||
AddEdge(node, referent, emptyStr);
|
||||
AddEdge(node, referent, nullptr);
|
||||
|
||||
::testing::NiceMock<MockWriter> writer;
|
||||
|
||||
// Should get the node with edges once.
|
||||
EXPECT_CALL(
|
||||
writer,
|
||||
writeNode(AllOf(EdgesLength(cx, 3),
|
||||
Edge(cx, 0, Field(&JS::ubi::Edge::name,
|
||||
UniqueUTF16StrEq(edgeName))),
|
||||
Edge(cx, 1, Field(&JS::ubi::Edge::name,
|
||||
UniqueUTF16StrEq(emptyStr))),
|
||||
Edge(cx, 2, Field(&JS::ubi::Edge::name,
|
||||
UniqueIsNull()))),
|
||||
_)
|
||||
)
|
||||
.Times(1)
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Should get the referent node that doesn't have any edges once.
|
||||
ExpectWriteNode(writer, referent);
|
||||
|
||||
JS::AutoCheckCannotGC noGC(cx);
|
||||
ASSERT_TRUE(WriteHeapGraph(cx,
|
||||
JS::ubi::Node(&node),
|
||||
writer,
|
||||
/* wantNames = */ true,
|
||||
/* zones = */ nullptr,
|
||||
noGC));
|
||||
});
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
// Test that everything in the heap graph gets serialized once, and only once.
|
||||
|
||||
#include "DevTools.h"
|
||||
|
||||
DEF_TEST(SerializesEverythingInHeapGraphOnce, {
|
||||
FakeNode nodeA;
|
||||
FakeNode nodeB;
|
||||
FakeNode nodeC;
|
||||
FakeNode nodeD;
|
||||
|
||||
AddEdge(nodeA, nodeB);
|
||||
AddEdge(nodeB, nodeC);
|
||||
AddEdge(nodeC, nodeD);
|
||||
AddEdge(nodeD, nodeA);
|
||||
|
||||
::testing::NiceMock<MockWriter> writer;
|
||||
|
||||
// Should serialize each node once.
|
||||
ExpectWriteNode(writer, nodeA);
|
||||
ExpectWriteNode(writer, nodeB);
|
||||
ExpectWriteNode(writer, nodeC);
|
||||
ExpectWriteNode(writer, nodeD);
|
||||
|
||||
JS::AutoCheckCannotGC noGC(cx);
|
||||
|
||||
ASSERT_TRUE(WriteHeapGraph(cx,
|
||||
JS::ubi::Node(&nodeA),
|
||||
writer,
|
||||
/* wantNames = */ false,
|
||||
/* zones = */ nullptr,
|
||||
noGC));
|
||||
});
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
// Test that a ubi::Node's typeName gets properly serialized into a core dump.
|
||||
|
||||
#include "DevTools.h"
|
||||
|
||||
using testing::Property;
|
||||
using testing::Return;
|
||||
|
||||
DEF_TEST(SerializesTypeNames, {
|
||||
FakeNode node;
|
||||
|
||||
::testing::NiceMock<MockWriter> writer;
|
||||
EXPECT_CALL(writer, writeNode(Property(&JS::ubi::Node::typeName,
|
||||
UTF16StrEq(u"FakeNode")),
|
||||
_))
|
||||
.Times(1)
|
||||
.WillOnce(Return(true));
|
||||
|
||||
JS::AutoCheckCannotGC noGC(cx);
|
||||
ASSERT_TRUE(WriteHeapGraph(cx,
|
||||
JS::ubi::Node(&node),
|
||||
writer,
|
||||
/* wantNames = */ true,
|
||||
/* zones = */ nullptr,
|
||||
noGC));
|
||||
});
|
||||
31
devtools/shared/heapsnapshot/tests/gtest/moz.build
Normal file
31
devtools/shared/heapsnapshot/tests/gtest/moz.build
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
Library('devtoolstests')
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'../..',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES = [
|
||||
'DeserializedNodeUbiNodes.cpp',
|
||||
'DeserializedStackFrameUbiStackFrames.cpp',
|
||||
'DoesCrossCompartmentBoundaries.cpp',
|
||||
'DoesntCrossCompartmentBoundaries.cpp',
|
||||
'SerializesEdgeNames.cpp',
|
||||
'SerializesEverythingInHeapGraphOnce.cpp',
|
||||
'SerializesTypeNames.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
|
||||
# THE MOCK_METHOD2 macro from gtest triggers this clang warning and it's hard
|
||||
# to work around, so we just ignore it.
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += ['-Wno-inconsistent-missing-override']
|
||||
|
||||
FINAL_LIBRARY = 'xul-gtest'
|
||||
Loading…
Add table
Add a link
Reference in a new issue