Backed out changeset ace4dd426349 (bug 972045) for mochitest failures.

This commit is contained in:
Ryan VanderMeulen 2014-04-24 15:10:44 -04:00
Родитель 7840ab12de
Коммит 8b7b5cc3a2
24 изменённых файлов: 5 добавлений и 1115 удалений

Просмотреть файл

@ -512,8 +512,7 @@ struct CompartmentStats
macro(Other, NotLiveGCThing, compartmentObject) \
macro(Other, NotLiveGCThing, crossCompartmentWrappersTable) \
macro(Other, NotLiveGCThing, regexpCompartment) \
macro(Other, NotLiveGCThing, debuggeesSet) \
macro(Other, IsLiveGCThing, savedStacksSet)
macro(Other, NotLiveGCThing, debuggeesSet)
CompartmentStats()
: FOR_EACH_SIZE(ZERO_SIZE)

Просмотреть файл

@ -23,7 +23,6 @@
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
#include "vm/ProxyObject.h"
#include "vm/SavedStacks.h"
#include "vm/TraceLogging.h"
#include "jscntxtinlines.h"
@ -851,25 +850,6 @@ CountHeap(JSContext *cx, unsigned argc, jsval *vp)
return true;
}
static bool
GetSavedFrameCount(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(cx->compartment()->savedStacks().count());
return true;
}
static bool
SaveStack(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<SavedFrame*> frame(cx);
if (!cx->compartment()->savedStacks().saveCurrentStack(cx, &frame))
return false;
args.rval().setObject(*frame.get());
return true;
}
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
static bool
OOMAfterAllocations(JSContext *cx, unsigned argc, jsval *vp)
@ -1570,15 +1550,6 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
" then you can provide an extra argument with some specific traceable\n"
" thing to count.\n"),
JS_FN_HELP("getSavedFrameCount", GetSavedFrameCount, 0, 0,
"getSavedFrameCount()",
" Return the number of SavedFrame instances stored in this compartment's\n"
" SavedStacks cache."),
JS_FN_HELP("saveStack", SaveStack, 0, 0,
"saveStack()",
" Capture a stack.\n"),
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 1, 0,
"oomAfterAllocations(count)",

Просмотреть файл

@ -1,3 +0,0 @@
// The SavedFrame constructor shouldn't have been exposed to JS on the global.
assertEq(typeof SavedFrame, "undefined");

Просмотреть файл

@ -1,38 +0,0 @@
// Test that we can save stacks with direct and indirect eval calls.
const directEval = (function iife() {
return eval("(" + function evalFrame() {
return saveStack();
} + "())");
}());
assertEq(directEval.source.contains("> eval"), true);
assertEq(directEval.functionDisplayName, "evalFrame");
assertEq(directEval.parent.source.contains("> eval"), true);
assertEq(directEval.parent.parent.source.contains("> eval"), false);
assertEq(directEval.parent.parent.functionDisplayName, "iife");
assertEq(directEval.parent.parent.parent.source.contains("> eval"), false);
assertEq(directEval.parent.parent.parent.parent, null);
const lave = eval;
const indirectEval = (function iife() {
return lave("(" + function evalFrame() {
return saveStack();
} + "())");
}());
assertEq(indirectEval.source.contains("> eval"), true);
assertEq(indirectEval.functionDisplayName, "evalFrame");
assertEq(indirectEval.parent.source.contains("> eval"), true);
assertEq(indirectEval.parent.parent.source.contains("> eval"), false);
assertEq(indirectEval.parent.parent.functionDisplayName, "iife");
assertEq(indirectEval.parent.parent.parent.source.contains("> eval"), false);
assertEq(indirectEval.parent.parent.parent.parent, null);

Просмотреть файл

@ -1,17 +0,0 @@
// Test the functionDisplayName of SavedFrame instances.
function uno() { return dos(); }
const dos = () => tres.quattro();
const tres = {
quattro: () => saveStack()
};
const frame = uno();
assertEq(frame.functionDisplayName, "tres.quattro");
assertEq(frame.parent.functionDisplayName, "dos");
assertEq(frame.parent.parent.functionDisplayName, "uno");
assertEq(frame.parent.parent.parent.functionDisplayName, null);
assertEq(frame.parent.parent.parent.parent, null);

Просмотреть файл

@ -1,76 +0,0 @@
// Test that SavedFrame instances get removed from the SavedStacks frames cache
// after a GC.
const FUZZ_FACTOR = 3;
function assertAboutEq(actual, expected) {
if (Math.abs(actual - expected) > FUZZ_FACTOR)
throw new Error("Assertion failed: expected about " + expected + ", got " + actual +
". FUZZ_FACTOR = " + FUZZ_FACTOR);
}
const stacks = [];
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
stacks.push(saveStack());
assertAboutEq(getSavedFrameCount(), 50);
while (stacks.length) {
stacks.pop();
}
gc();
stacks = null;
gc();
assertAboutEq(getSavedFrameCount(), 0);

Просмотреть файл

@ -1,15 +0,0 @@
// Test that we can save stacks which have generator frames.
const { value: frame } = (function iife1() {
return (function* generator() {
yield (function iife2() {
return saveStack();
}());
}()).next();
}());
assertEq(frame.functionDisplayName, "iife2");
assertEq(frame.parent.functionDisplayName, "generator");
assertEq(frame.parent.parent.functionDisplayName, "iife1");
assertEq(frame.parent.parent.parent.functionDisplayName, null);
assertEq(frame.parent.parent.parent.parent, null);

Просмотреть файл

@ -1,25 +0,0 @@
// Test that we can save stacks with getter and setter function frames.
function assertStackLengthEq(stack, expectedLength) {
let actual = 0;
while (stack) {
actual++;
stack = stack.parent;
}
assertEq(actual, expectedLength);
}
const get = { get s() { return saveStack(); } }.s;
assertStackLengthEq(get, 2);
let set;
try {
({
set s(v) {
throw saveStack();
}
}).s = 1;
} catch (s) {
set = s;
}
assertStackLengthEq(set, 2);

Просмотреть файл

@ -1,21 +0,0 @@
// Test that you can't call the SavedFrame constructor and can only use
// SavedFrame's getters on SavedFrame instances.
load(libdir + "asserts.js");
let proto = Object.getPrototypeOf(saveStack());
// Can't create new SavedFrame instances by hand.
assertThrowsInstanceOf(() => {
new proto.constructor();
}, TypeError);
for (let p of ["source", "line", "column", "functionDisplayName", "parent"]) {
// The getters shouldn't work on the prototype.
assertThrowsInstanceOf(() => proto[p], TypeError);
// Nor should they work on random objects.
let o = {};
Object.defineProperty(o, p, Object.getOwnPropertyDescriptor(proto, p));
assertThrowsInstanceOf(() => o[p], TypeError);
}

Просмотреть файл

@ -1,12 +0,0 @@
// Test that we can save stacks with native code on the stack.
// Unlike Array.prototype.map, Array.prototype.filter is not self-hosted.
const filter = (function iife() {
try {
[3].filter(n => { throw saveStack() });
} catch (s) {
return s;
}
}());
assertEq(filter.parent.functionDisplayName, "iife");

Просмотреть файл

@ -1,70 +0,0 @@
// Test that SavedFrame.prototype.parent gives the next older frame whose
// principals are subsumed by the caller's principals.
// Given a string of letters |expected|, say "abc", assert that the stack
// contains calls to a series of functions named by the next letter from
// the string, say a, b, and then c. Younger frames appear earlier in
// |expected| than older frames.
function check(expected, stack) {
print("check(" + uneval(expected) + ") against:\n" + stack);
count++;
while (stack.length && expected.length) {
assertEq(stack.shift(), expected[0]);
expected = expected.slice(1);
}
if (expected.length > 0) {
throw new Error("Missing frames for: " + expected);
}
if (stack.length > 0 && !stack.every(s => s === null)) {
throw new Error("Unexpected extra frame(s):\n" + stack);
}
}
// Go from a SavedFrame linked list to an array of function display names.
function extract(stack) {
const results = [];
while (stack) {
results.push(stack.functionDisplayName);
stack = stack.parent;
}
return results;
}
const low = newGlobal({ principal: 0 });
const mid = newGlobal({ principal: 0xffff });
const high = newGlobal({ principal: 0xfffff });
var count = 0;
eval('function a() { check("a", extract(saveStack())); b(); }');
low .eval('function b() { check("b", extract(saveStack())); c(); }');
mid .eval('function c() { check("cba", extract(saveStack())); d(); }');
high.eval('function d() { check("dcba", extract(saveStack())); e(); }');
eval('function e() { check("edcba", extract(saveStack())); f(); }'); // no principal, so checks skipped
low .eval('function f() { check("fb", extract(saveStack())); g(); }');
mid .eval('function g() { check("gfecba", extract(saveStack())); h(); }');
high.eval('function h() { check("hgfedcba", extract(saveStack())); }');
// Make everyone's functions visible to each other, as needed.
b = low .b;
low .c = mid .c;
mid .d = high.d;
high.e = e;
f = low .f;
low .g = mid .g;
mid .h = high.h;
low.check = mid.check = high.check = check;
// They each must have their own extract so that CCWs don't mess up the
// principals when we ask for the parent property.
low. eval("" + extract);
mid. eval("" + extract);
high.eval("" + extract);
// Kick the whole process off.
a();
assertEq(count, 8);

Просмотреть файл

@ -1,56 +0,0 @@
// Test that SavedFrame.prototype.toString only shows frames whose principal is
// subsumed by the caller's principal.
var count = 0;
// Given a string of letters |expected|, say "abc", assert that the stack
// contains calls to a series of functions named by the next letter from
// the string, say a, b, and then c. Younger frames appear earlier in
// |expected| than older frames.
function check(expected, stack) {
print("check(" + uneval(expected) + ") against:\n" + stack);
count++;
// Extract only the function names from the stack trace. Omit the frames
// for the top-level evaluation, if it is present.
const frames = stack
.split("\n")
.filter(f => f.match(/^.@/))
.map(f => f.replace(/@.*$/g, ""));
// Check the function names against the expected sequence.
assertEq(frames.length, expected.length);
for (var i = 0; i < expected.length; i++) {
assertEq(frames[i], expected[i]);
}
}
var low = newGlobal({ principal: 0 });
var mid = newGlobal({ principal: 0xffff });
var high = newGlobal({ principal: 0xfffff });
eval('function a() { check("a", saveStack().toString()); b(); }');
low .eval('function b() { check("b", saveStack().toString()); c(); }');
mid .eval('function c() { check("cba", saveStack().toString()); d(); }');
high.eval('function d() { check("dcba", saveStack().toString()); e(); }');
eval('function e() { check("edcba", saveStack().toString()); f(); }'); // no principal, so checks skipped
low .eval('function f() { check("fb", saveStack().toString()); g(); }');
mid .eval('function g() { check("gfecba", saveStack().toString()); h(); }');
high.eval('function h() { check("hgfedcba", saveStack().toString()); }');
// Make everyone's functions visible to each other, as needed.
b = low .b;
low .c = mid .c;
mid .d = high.d;
high.e = e;
f = low .f;
low .g = mid .g;
mid .h = high.h;
low.check = mid.check = high.check = check;
// Kick the whole process off.
a();
assertEq(count, 8);

Просмотреть файл

@ -1,10 +0,0 @@
// Test that we can save stacks with proxy handler frames.
const stack = (function iife() {
return (new Proxy({}, {
get: function get(t, n, r) { return saveStack(); }
})).stack;
}());
assertEq(stack.functionDisplayName, "get");
assertEq(stack.parent.functionDisplayName, "iife");

Просмотреть файл

@ -1,12 +0,0 @@
// Test that the same saved stack is only ever allocated once.
const stacks = [];
for (let i = 0; i < 10; i++) {
stacks.push(saveStack());
}
const s = stacks.pop();
for (let stack of stacks) {
assertEq(s, stack);
}

Просмотреть файл

@ -1,26 +0,0 @@
// Test that we can save stacks with self-hosted function frames in them.
const map = (function () {
return [3].map(n => saveStack()).pop();
}());
assertEq(map.parent.functionDisplayName, "map");
assertEq(map.parent.source, "self-hosted");
const reduce = (function () {
return [3].reduce(() => saveStack(), 3);
}());
assertEq(reduce.parent.functionDisplayName, "reduce");
assertEq(reduce.parent.source, "self-hosted");
const forEach = (function () {
try {
[3].forEach(n => { throw saveStack() });
} catch (s) {
return s;
}
}());
assertEq(forEach.parent.functionDisplayName, "forEach");
assertEq(forEach.parent.source, "self-hosted");

Просмотреть файл

@ -1,19 +0,0 @@
// Test that parent frames are shared when the older portions of two stacks are
// the same.
let f1, f2;
function dos() {
f1 = saveStack();
f2 = saveStack();
}
(function uno() {
dos();
}());
// Different youngest frames.
assertEq(f1 == f2, false);
// However the parents should be the same.
assertEq(f1.parent, f2.parent);

Просмотреть файл

@ -1,8 +0,0 @@
// Test that stringify'ing a saved frame with self-hosted parent frames doesn't
// include the self-hosted parent frame in the output.
const map = (function () {
return [3].map(n => saveStack()).pop();
}());
assertEq(map.toString().contains("@self-hosted:"), false);

Просмотреть файл

@ -113,9 +113,6 @@ JSCompartment::init(JSContext *cx)
if (!enumerators)
return false;
if (!savedStacks_.init())
return false;
return debuggees.init(0);
}
@ -566,7 +563,6 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
sweepNewTypeObjectTable(newTypeObjects);
sweepNewTypeObjectTable(lazyTypeObjects);
sweepCallsiteClones();
savedStacks_.sweep(rt);
if (global_ && IsObjectAboutToBeFinalized(global_.unsafeGet()))
global_ = nullptr;
@ -669,8 +665,6 @@ JSCompartment::clearTables()
newTypeObjects.clear();
if (lazyTypeObjects.initialized())
lazyTypeObjects.clear();
if (savedStacks_.initialized())
savedStacks_.clear();
}
void
@ -921,8 +915,7 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t *shapesCompartmentTables,
size_t *crossCompartmentWrappersArg,
size_t *regexpCompartment,
size_t *debuggeesSet,
size_t *savedStacksSet)
size_t *debuggeesSet)
{
*compartmentObject += mallocSizeOf(this);
types.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
@ -934,7 +927,6 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
*crossCompartmentWrappersArg += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf);
*regexpCompartment += regExps.sizeOfExcludingThis(mallocSizeOf);
*debuggeesSet += debuggees.sizeOfExcludingThis(mallocSizeOf);
*savedStacksSet += savedStacks_.sizeOfExcludingThis(mallocSizeOf);
}
void

Просмотреть файл

@ -13,7 +13,6 @@
#include "gc/Zone.h"
#include "vm/GlobalObject.h"
#include "vm/PIC.h"
#include "vm/SavedStacks.h"
namespace js {
@ -199,8 +198,6 @@ struct JSCompartment
private:
js::ObjectMetadataCallback objectMetadataCallback;
js::SavedStacks savedStacks_;
js::WrapperMap crossCompartmentWrappers;
public:
@ -227,8 +224,7 @@ struct JSCompartment
size_t *shapesCompartmentTables,
size_t *crossCompartmentWrappers,
size_t *regexpCompartment,
size_t *debuggeesSet,
size_t *savedStacksSet);
size_t *debuggeesSet);
/*
* Shared scope property tree, and arena-pool for allocating its nodes.
@ -346,8 +342,6 @@ struct JSCompartment
return objectMetadataCallback(cx, obj);
}
js::SavedStacks &savedStacks() { return savedStacks_; }
void findOutgoingEdges(js::gc::ComponentFinder<JS::Zone> &finder);
js::DtoaCache dtoaCache;

Просмотреть файл

@ -179,7 +179,6 @@ UNIFIED_SOURCES += [
'vm/RegExpObject.cpp',
'vm/RegExpStatics.cpp',
'vm/Runtime.cpp',
'vm/SavedStacks.cpp',
'vm/ScopeObject.cpp',
'vm/SelfHosting.cpp',
'vm/Shape.cpp',

Просмотреть файл

@ -259,8 +259,7 @@ StatsCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment)
&cStats.shapesMallocHeapCompartmentTables,
&cStats.crossCompartmentWrappersTable,
&cStats.regexpCompartment,
&cStats.debuggeesSet,
&cStats.savedStacksSet);
&cStats.debuggeesSet);
}
static void

Просмотреть файл

@ -1,512 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "vm/SavedStacks.h"
#include "jscompartment.h"
#include "jsnum.h"
#include "vm/GlobalObject.h"
#include "vm/StringBuffer.h"
#include "jsobjinlines.h"
using mozilla::AddToHash;
using mozilla::HashString;
namespace js {
/* static */ HashNumber
SavedFrame::HashPolicy::hash(const Lookup &lookup)
{
return AddToHash(HashString(lookup.source->chars(), lookup.source->length()),
lookup.line,
lookup.column,
lookup.functionDisplayName,
SavedFramePtrHasher::hash(lookup.parent),
JSPrincipalsPtrHasher::hash(lookup.principals));
}
/* static */ bool
SavedFrame::HashPolicy::match(SavedFrame *existing, const Lookup &lookup)
{
if (existing->getLine() != lookup.line)
return false;
if (existing->getColumn() != lookup.column)
return false;
if (existing->getParent() != lookup.parent)
return false;
if (existing->getPrincipals() != lookup.principals)
return false;
JSAtom *source = existing->getSource();
if (source->length() != lookup.source->length())
return false;
if (source != lookup.source)
return false;
JSAtom *functionDisplayName = existing->getFunctionDisplayName();
if (functionDisplayName) {
if (!lookup.functionDisplayName)
return false;
if (functionDisplayName->length() != lookup.functionDisplayName->length())
return false;
if (0 != CompareAtoms(functionDisplayName, lookup.functionDisplayName))
return false;
} else if (lookup.functionDisplayName) {
return false;
}
return true;
}
/* static */ void
SavedFrame::HashPolicy::rekey(Key &key, const Key &newKey)
{
key = newKey;
}
/* static */ const Class SavedFrame::class_ = {
"SavedFrame",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT),
JS_PropertyStub, // addProperty
JS_DeletePropertyStub, // delProperty
JS_PropertyStub, // getProperty
JS_StrictPropertyStub, // setProperty
JS_EnumerateStub, // enumerate
JS_ResolveStub, // resolve
JS_ConvertStub, // convert
SavedFrame::finalize // finalize
};
/* static */ void
SavedFrame::finalize(FreeOp *fop, JSObject *obj)
{
JSPrincipals *p = obj->as<SavedFrame>().getPrincipals();
if (p) {
JSRuntime *rt = obj->runtimeFromMainThread();
JS_DropPrincipals(rt, p);
}
}
JSAtom *
SavedFrame::getSource()
{
const Value &v = getReservedSlot(JSSLOT_SOURCE);
JSString *s = v.toString();
return &s->asAtom();
}
size_t
SavedFrame::getLine()
{
const Value &v = getReservedSlot(JSSLOT_LINE);
return v.toInt32();
}
size_t
SavedFrame::getColumn()
{
const Value &v = getReservedSlot(JSSLOT_COLUMN);
return v.toInt32();
}
JSAtom *
SavedFrame::getFunctionDisplayName()
{
const Value &v = getReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME);
if (v.isNull())
return nullptr;
JSString *s = v.toString();
return &s->asAtom();
}
SavedFrame *
SavedFrame::getParent()
{
const Value &v = getReservedSlot(JSSLOT_PARENT);
return v.isObject() ? &v.toObject().as<SavedFrame>() : nullptr;
}
JSPrincipals *
SavedFrame::getPrincipals()
{
const Value &v = getReservedSlot(JSSLOT_PRINCIPALS);
if (v.isUndefined())
return nullptr;
return static_cast<JSPrincipals *>(v.toPrivate());
}
void
SavedFrame::initFromLookup(Lookup &lookup)
{
JS_ASSERT(lookup.source);
JS_ASSERT(getReservedSlot(JSSLOT_SOURCE).isUndefined());
setReservedSlot(JSSLOT_SOURCE, StringValue(lookup.source));
setReservedSlot(JSSLOT_LINE, NumberValue(lookup.line));
setReservedSlot(JSSLOT_COLUMN, NumberValue(lookup.column));
setReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME,
lookup.functionDisplayName
? StringValue(lookup.functionDisplayName)
: NullValue());
setReservedSlot(JSSLOT_PARENT, ObjectOrNullValue(lookup.parent));
setReservedSlot(JSSLOT_PRIVATE_PARENT, PrivateValue(lookup.parent));
JS_ASSERT(getReservedSlot(JSSLOT_PRINCIPALS).isUndefined());
if (lookup.principals)
JS_HoldPrincipals(lookup.principals);
setReservedSlot(JSSLOT_PRINCIPALS, PrivateValue(lookup.principals));
}
bool
SavedFrame::parentMoved()
{
const Value &v = getReservedSlot(JSSLOT_PRIVATE_PARENT);
JSObject *p = static_cast<JSObject *>(v.toPrivate());
return p == getParent();
}
void
SavedFrame::updatePrivateParent()
{
setReservedSlot(JSSLOT_PRIVATE_PARENT, PrivateValue(getParent()));
}
bool
SavedFrame::isSelfHosted()
{
JSAtom *source = getSource();
return StringEqualsAscii(source, "self-hosted");
}
/* static */ bool
SavedFrame::construct(JSContext *cx, unsigned argc, Value *vp)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
"SavedFrame");
return false;
}
/* static */ SavedFrame *
SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName)
{
const Value &thisValue = args.thisv();
if (!thisValue.isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
return nullptr;
}
JSObject &thisObject = thisValue.toObject();
if (!thisObject.is<SavedFrame>()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
SavedFrame::class_.name, fnName, thisObject.getClass()->name);
return nullptr;
}
// Check for SavedFrame.prototype, which has the same class as SavedFrame
// instances, however doesn't actually represent a captured stack frame. It
// is the only object that is<SavedFrame>() but doesn't have a source.
if (thisObject.getReservedSlot(JSSLOT_SOURCE).isNull()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
SavedFrame::class_.name, fnName, "prototype object");
return nullptr;
}
return &thisObject.as<SavedFrame>();
}
// Get the SavedFrame * from the current this value and handle any errors that
// might occur therein.
//
// These parameters must already exist when calling this macro:
// - JSContext *cx
// - unsigned argc
// - Value *vp
// - const char *fnName
// These parameters will be defined after calling this macro:
// - CallArgs args
// - Rooted<SavedFrame *> frame (will be non-null)
#define THIS_SAVEDFRAME(cx, argc, vp, fnName, args, frame) \
CallArgs args = CallArgsFromVp(argc, vp); \
Rooted<SavedFrame *> frame(cx, checkThis(cx, args, fnName)); \
if (!frame) \
return false
/* static */ bool
SavedFrame::sourceProperty(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "(get source)", args, frame);
args.rval().setString(frame->getSource());
return true;
}
/* static */ bool
SavedFrame::lineProperty(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "(get line)", args, frame);
uint32_t line = frame->getLine();
args.rval().setNumber(line);
return true;
}
/* static */ bool
SavedFrame::columnProperty(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "(get column)", args, frame);
uint32_t column = frame->getColumn();
args.rval().setNumber(column);
return true;
}
/* static */ bool
SavedFrame::functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", args, frame);
RootedAtom name(cx, frame->getFunctionDisplayName());
if (name)
args.rval().setString(name);
else
args.rval().setNull();
return true;
}
/* static */ bool
SavedFrame::parentProperty(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", args, frame);
JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes;
JSPrincipals *principals = cx->compartment()->principals;
do
frame = frame->getParent();
while (frame && principals && subsumes &&
!subsumes(principals, frame->getPrincipals()));
args.rval().setObjectOrNull(frame);
return true;
}
/* static */ const JSPropertySpec SavedFrame::properties[] = {
JS_PSG("source", SavedFrame::sourceProperty, 0),
JS_PSG("line", SavedFrame::lineProperty, 0),
JS_PSG("column", SavedFrame::columnProperty, 0),
JS_PSG("functionDisplayName", SavedFrame::functionDisplayNameProperty, 0),
JS_PSG("parent", SavedFrame::parentProperty, 0),
JS_PS_END
};
/* static */ bool
SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp)
{
THIS_SAVEDFRAME(cx, argc, vp, "toString", args, frame);
StringBuffer sb(cx);
JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes;
JSPrincipals *principals = cx->compartment()->principals;
do {
if (principals && subsumes && !subsumes(principals, frame->getPrincipals()))
continue;
if (frame->isSelfHosted())
continue;
RootedAtom name(cx, frame->getFunctionDisplayName());
if ((name && !sb.append(name))
|| !sb.append('@')
|| !sb.append(frame->getSource())
|| !sb.append(':')
|| !NumberValueToStringBuffer(cx, NumberValue(frame->getLine()), sb)
|| !sb.append(':')
|| !NumberValueToStringBuffer(cx, NumberValue(frame->getColumn()), sb)
|| !sb.append('\n')) {
return false;
}
} while ((frame = frame->getParent()));
args.rval().setString(sb.finishString());
return true;
}
/* static */ const JSFunctionSpec SavedFrame::methods[] = {
JS_FN("toString", SavedFrame::toStringMethod, 0, 0),
JS_FS_END
};
bool
SavedStacks::init()
{
return frames.init();
}
bool
SavedStacks::saveCurrentStack(JSContext *cx, MutableHandle<SavedFrame*> frame)
{
JS_ASSERT(initialized());
JS_ASSERT(&cx->compartment()->savedStacks() == this);
ScriptFrameIter iter(cx);
return insertFrames(cx, iter, frame);
}
void
SavedStacks::sweep(JSRuntime *rt)
{
if (frames.initialized()) {
for (SavedFrame::Set::Enum e(frames); !e.empty(); e.popFront()) {
JSObject *obj = static_cast<JSObject *>(e.front());
JSObject *temp = obj;
if (IsObjectAboutToBeFinalized(&obj)) {
e.removeFront();
} else {
SavedFrame *frame = &obj->as<SavedFrame>();
bool parentMoved = frame->parentMoved();
if (parentMoved) {
frame->updatePrivateParent();
}
if (obj != temp || parentMoved) {
Rooted<SavedFrame*> parent(rt, frame->getParent());
e.rekeyFront(SavedFrame::Lookup(frame->getSource(),
frame->getLine(),
frame->getColumn(),
frame->getFunctionDisplayName(),
parent,
frame->getPrincipals()),
frame);
}
}
}
}
if (savedFrameProto && IsObjectAboutToBeFinalized(&savedFrameProto)) {
savedFrameProto = nullptr;
}
}
uint32_t
SavedStacks::count()
{
JS_ASSERT(initialized());
return frames.count();
}
void
SavedStacks::clear()
{
frames.clear();
}
size_t
SavedStacks::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
{
return frames.sizeOfExcludingThis(mallocSizeOf);
}
bool
SavedStacks::insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandle<SavedFrame*> frame)
{
if (iter.done()) {
frame.set(nullptr);
return true;
}
ScriptFrameIter thisFrame(iter);
Rooted<SavedFrame*> parentFrame(cx);
if (!insertFrames(cx, ++iter, &parentFrame))
return false;
RootedScript script(cx, thisFrame.script());
RootedFunction callee(cx, thisFrame.maybeCallee());
const char *filename = script->filename();
RootedAtom source(cx, Atomize(cx, filename, strlen(filename)));
if (!source)
return false;
uint32_t column;
uint32_t line = PCToLineNumber(script, thisFrame.pc(), &column);
SavedFrame::Lookup lookup(source,
line,
column,
callee ? callee->displayAtom() : nullptr,
parentFrame,
thisFrame.compartment()->principals);
frame.set(getOrCreateSavedFrame(cx, lookup));
return frame.address() != nullptr;
}
SavedFrame *
SavedStacks::getOrCreateSavedFrame(JSContext *cx, SavedFrame::Lookup &lookup)
{
SavedFrame::Set::AddPtr p = frames.lookupForAdd(lookup);
if (p)
return *p;
Rooted<SavedFrame *> frame(cx, createFrameFromLookup(cx, lookup));
if (!frame)
return nullptr;
if (!frames.relookupOrAdd(p, lookup, frame))
return nullptr;
return frame;
}
JSObject *
SavedStacks::getOrCreateSavedFramePrototype(JSContext *cx)
{
if (savedFrameProto)
return savedFrameProto;
Rooted<GlobalObject *> global(cx, cx->compartment()->maybeGlobal());
if (!global)
return nullptr;
savedFrameProto = js_InitClass(cx, global, global->getOrCreateObjectPrototype(cx),
&SavedFrame::class_, SavedFrame::construct, 0,
SavedFrame::properties, SavedFrame::methods, nullptr, nullptr);
// The only object with the SavedFrame::class_ that doesn't have a source
// should be the prototype.
savedFrameProto->setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue());
return savedFrameProto;
}
SavedFrame *
SavedStacks::createFrameFromLookup(JSContext *cx, SavedFrame::Lookup &lookup)
{
RootedObject proto(cx, getOrCreateSavedFramePrototype(cx));
if (!proto)
return nullptr;
JS_ASSERT(proto->compartment() == cx->compartment());
RootedObject global(cx, cx->compartment()->maybeGlobal());
if (!global)
return nullptr;
JS_ASSERT(global->compartment() == cx->compartment());
RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto, global));
if (!frameObj)
return nullptr;
SavedFrame &f = frameObj->as<SavedFrame>();
f.initFromLookup(lookup);
return &f;
}
} /* namespace js */

Просмотреть файл

@ -1,144 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 vm_SavedStacks_h
#define vm_SavedStacks_h
#include "jscntxt.h"
#include "js/HashTable.h"
#include "vm/Stack.h"
namespace js {
class SavedFrame : public JSObject {
friend class SavedStacks;
public:
static const Class class_;
static void finalize(FreeOp *fop, JSObject *obj);
// Prototype methods and properties to be exposed to JS.
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static bool construct(JSContext *cx, unsigned argc, Value *vp);
static bool sourceProperty(JSContext *cx, unsigned argc, Value *vp);
static bool lineProperty(JSContext *cx, unsigned argc, Value *vp);
static bool columnProperty(JSContext *cx, unsigned argc, Value *vp);
static bool functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp);
static bool parentProperty(JSContext *cx, unsigned argc, Value *vp);
static bool toStringMethod(JSContext *cx, unsigned argc, Value *vp);
// Convenient getters for SavedFrame's reserved slots for use from C++.
JSAtom *getSource();
size_t getLine();
size_t getColumn();
JSAtom *getFunctionDisplayName();
SavedFrame *getParent();
JSPrincipals *getPrincipals();
bool isSelfHosted();
struct Lookup;
struct HashPolicy;
typedef HashSet<SavedFrame *,
HashPolicy,
SystemAllocPolicy> Set;
private:
void initFromLookup(Lookup &lookup);
enum {
// The reserved slots in the SavedFrame class.
JSSLOT_SOURCE,
JSSLOT_LINE,
JSSLOT_COLUMN,
JSSLOT_FUNCTIONDISPLAYNAME,
JSSLOT_PARENT,
JSSLOT_PRINCIPALS,
JSSLOT_PRIVATE_PARENT,
// The total number of reserved slots in the SavedFrame class.
JSSLOT_COUNT
};
// Because we hash the parent pointer, we need to rekey a saved frame
// whenever its parent was relocated by the GC. However, the GC doesn't
// notify us when this occurs. As a work around, we keep a duplicate copy of
// the parent pointer as a private value in a reserved slot. Whenever the
// private value parent pointer doesn't match the regular parent pointer, we
// know that GC moved the parent and we need to update our private value and
// rekey the saved frame in its hash set. These two methods are helpers for
// this process.
bool parentMoved();
void updatePrivateParent();
static SavedFrame *checkThis(JSContext *cx, CallArgs &args, const char *fnName);
};
struct SavedFrame::Lookup {
Lookup(JSAtom *source, size_t line, size_t column, JSAtom *functionDisplayName,
Handle<SavedFrame*> parent, JSPrincipals *principals)
: source(source),
line(line),
column(column),
functionDisplayName(functionDisplayName),
parent(parent),
principals(principals)
{
JS_ASSERT(source);
}
JSAtom *source;
size_t line;
size_t column;
JSAtom *functionDisplayName;
Handle<SavedFrame*> parent;
JSPrincipals *principals;
};
struct SavedFrame::HashPolicy
{
typedef SavedFrame::Lookup Lookup;
typedef PointerHasher<SavedFrame *, 3> SavedFramePtrHasher;
typedef PointerHasher<JSPrincipals *, 3> JSPrincipalsPtrHasher;
static HashNumber hash(const Lookup &lookup);
static bool match(SavedFrame *existing, const Lookup &lookup);
typedef SavedFrame* Key;
static void rekey(Key &key, const Key &newKey);
};
class SavedStacks {
public:
SavedStacks() : frames(), savedFrameProto(nullptr) { }
bool init();
bool initialized() const { return frames.initialized(); }
bool saveCurrentStack(JSContext *cx, MutableHandle<SavedFrame*> frame);
void sweep(JSRuntime *rt);
uint32_t count();
void clear();
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
private:
SavedFrame::Set frames;
JSObject *savedFrameProto;
bool insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandle<SavedFrame*> frame);
SavedFrame *getOrCreateSavedFrame(JSContext *cx, SavedFrame::Lookup &lookup);
// |SavedFrame.prototype| is created lazily and held weakly. It should only
// be accessed through this method.
JSObject *getOrCreateSavedFramePrototype(JSContext *cx);
SavedFrame *createFrameFromLookup(JSContext *cx, SavedFrame::Lookup &lookup);
};
} /* namespace js */
#endif /* vm_SavedStacks_h */

Просмотреть файл

@ -677,7 +677,7 @@ FrameIter::FrameIter(const FrameIter &other)
: data_(other.data_)
#ifdef JS_ION
, ionInlineFrames_(other.data_.cx_,
data_.jitFrames_.isIonJS() ? &other.ionInlineFrames_ : nullptr)
data_.jitFrames_.isScripted() ? &other.ionInlineFrames_ : nullptr)
#endif
{
}