Merge inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-10-12 14:26:17 -04:00
commit ae61dad479
25 changed files with 309 additions and 144 deletions

View File

@ -34,6 +34,7 @@
#include "JavaScriptChild.h"
#include "JavaScriptParent.h"
#include "nsDOMLists.h"
#include "nsPrintfCString.h"
#include <algorithm>
#ifdef ANDROID
@ -1009,6 +1010,169 @@ nsFrameMessageManager::Disconnect(bool aRemoveFromParent)
}
}
namespace {
struct MessageManagerReferentCount {
MessageManagerReferentCount() : strong(0), weakAlive(0), weakDead(0) {}
size_t strong;
size_t weakAlive;
size_t weakDead;
nsCOMArray<nsIAtom> suspectMessages;
nsDataHashtable<nsPtrHashKey<nsIAtom>, uint32_t> messageCounter;
};
} // anonymous namespace
namespace mozilla {
namespace dom {
class MessageManagerReporter MOZ_FINAL : public nsIMemoryReporter
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMEMORYREPORTER
protected:
static const size_t kSuspectReferentCount = 300;
void CountReferents(nsFrameMessageManager* aMessageManager,
MessageManagerReferentCount* aReferentCount);
};
NS_IMPL_ISUPPORTS1(MessageManagerReporter, nsIMemoryReporter)
void
MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
MessageManagerReferentCount* aReferentCount)
{
for (uint32_t i = 0; i < aMessageManager->mListeners.Length(); i++) {
const nsMessageListenerInfo& listenerInfo = aMessageManager->mListeners[i];
if (listenerInfo.mWeakListener) {
nsCOMPtr<nsISupports> referent =
do_QueryReferent(listenerInfo.mWeakListener);
if (referent) {
aReferentCount->weakAlive++;
} else {
aReferentCount->weakDead++;
}
} else {
aReferentCount->strong++;
}
uint32_t oldCount = 0;
aReferentCount->messageCounter.Get(listenerInfo.mMessage, &oldCount);
uint32_t currentCount = oldCount + 1;
aReferentCount->messageCounter.Put(listenerInfo.mMessage, currentCount);
// Keep track of messages that have a suspiciously large
// number of referents (symptom of leak).
if (currentCount == kSuspectReferentCount) {
aReferentCount->suspectMessages.AppendElement(listenerInfo.mMessage);
}
}
// Add referent count in child managers because the listeners
// participate in messages dispatched from parent message manager.
for (uint32_t i = 0; i < aMessageManager->mChildManagers.Length(); i++) {
nsRefPtr<nsFrameMessageManager> mm =
static_cast<nsFrameMessageManager*>(aMessageManager->mChildManagers[i]);
CountReferents(mm, aReferentCount);
}
}
NS_IMETHODIMP
MessageManagerReporter::GetName(nsACString& aName)
{
aName.AssignLiteral("message-manager");
return NS_OK;
}
static nsresult
ReportReferentCount(const char* aManagerType,
const MessageManagerReferentCount& aReferentCount,
nsIMemoryReporterCallback* aCb,
nsISupports* aClosure)
{
#define REPORT(_path, _amount, _desc) \
do { \
nsresult rv; \
rv = aCb->Callback(EmptyCString(), _path, \
nsIMemoryReporter::KIND_OTHER, \
nsIMemoryReporter::UNITS_COUNT, _amount, \
_desc, aClosure); \
NS_ENSURE_SUCCESS(rv, rv); \
} while (0)
REPORT(nsPrintfCString("message-manager/referent/%s/strong", aManagerType),
aReferentCount.strong,
nsPrintfCString("The number of strong referents held by the message "
"manager in the %s manager.", aManagerType));
REPORT(nsPrintfCString("message-manager/referent/%s/weak/alive", aManagerType),
aReferentCount.weakAlive,
nsPrintfCString("The number of weak referents that are still alive "
"held by the message manager in the %s manager.",
aManagerType));
REPORT(nsPrintfCString("message-manager/referent/%s/weak/dead", aManagerType),
aReferentCount.weakDead,
nsPrintfCString("The number of weak referents that are dead "
"held by the message manager in the %s manager.",
aManagerType));
for (uint32_t i = 0; i < aReferentCount.suspectMessages.Length(); i++) {
uint32_t totalReferentCount = 0;
aReferentCount.messageCounter.Get(aReferentCount.suspectMessages[i],
&totalReferentCount);
nsAtomCString suspect(aReferentCount.suspectMessages[i]);
REPORT(nsPrintfCString("message-manager-suspect/%s/referent(message=%s)",
aManagerType, suspect.get()), totalReferentCount,
nsPrintfCString("A message in the %s message manager with a "
"suspiciously large number of referents (symptom "
"of a leak).", aManagerType));
}
#undef REPORT
return NS_OK;
}
NS_IMETHODIMP
MessageManagerReporter::CollectReports(nsIMemoryReporterCallback* aCb,
nsISupports* aClosure)
{
nsresult rv;
if (XRE_GetProcessType() == GeckoProcessType_Default) {
nsCOMPtr<nsIMessageBroadcaster> globalmm =
do_GetService("@mozilla.org/globalmessagemanager;1");
if (globalmm) {
nsRefPtr<nsFrameMessageManager> mm =
static_cast<nsFrameMessageManager*>(globalmm.get());
MessageManagerReferentCount count;
CountReferents(mm, &count);
rv = ReportReferentCount("global-manager", count, aCb, aClosure);
NS_ENSURE_SUCCESS(rv, rv);
}
}
if (nsFrameMessageManager::sParentProcessManager) {
MessageManagerReferentCount count;
CountReferents(nsFrameMessageManager::sParentProcessManager, &count);
rv = ReportReferentCount("parent-process-manager", count, aCb, aClosure);
NS_ENSURE_SUCCESS(rv, rv);
}
if (nsFrameMessageManager::sChildProcessManager) {
MessageManagerReferentCount count;
CountReferents(nsFrameMessageManager::sChildProcessManager, &count);
rv = ReportReferentCount("child-process-manager", count, aCb, aClosure);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla
nsresult
NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult)
{
@ -1017,6 +1181,7 @@ NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult)
nsFrameMessageManager* mm = new nsFrameMessageManager(nullptr,
nullptr,
MM_CHROME | MM_GLOBAL | MM_BROADCASTER);
NS_RegisterMemoryReporter(new MessageManagerReporter());
return CallQueryInterface(mm, aResult);
}
@ -1538,6 +1703,7 @@ NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
cb = new SameChildProcessMessageManagerCallback();
} else {
cb = new ChildProcessMessageManagerCallback();
NS_RegisterMemoryReporter(new MessageManagerReporter());
}
nsFrameMessageManager* mm = new nsFrameMessageManager(cb,
nullptr,

View File

@ -32,6 +32,7 @@ class ContentParent;
class ContentChild;
struct StructuredCloneData;
class ClonedMessageData;
class MessageManagerReporter;
namespace ipc {
@ -143,6 +144,7 @@ class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
public nsIFrameScriptLoader,
public nsIProcessChecker
{
friend class mozilla::dom::MessageManagerReporter;
typedef mozilla::dom::StructuredCloneData StructuredCloneData;
public:
nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,

View File

@ -7,7 +7,6 @@
XPIDL_SOURCES += [
'nsIContactProperties.idl',
'nsIDOMContactManager.idl',
'nsIDOMMozContactChangeEvent.idl',
]
XPIDL_MODULE = 'dom_contacts'

View File

@ -1,24 +0,0 @@
/* 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 "nsIDOMEvent.idl"
[scriptable, builtinclass, uuid(7ee758eb-9353-4ade-8715-9953ea512ee2)]
interface nsIDOMMozContactChangeEvent : nsIDOMEvent
{
readonly attribute DOMString contactID;
readonly attribute DOMString reason;
[noscript] void initMozContactChangeEvent(in DOMString aType,
in boolean aCanBubble,
in boolean aCancelable,
in DOMString aContactID,
in DOMString aReason);
};
dictionary MozContactChangeEventInit : EventInit
{
DOMString contactID;
DOMString reason;
};

View File

@ -7,11 +7,11 @@
interfaces = [
'base',
'canvas',
'contacts',
'core',
'html',
'events',
'devicestorage',
'contacts',
'settings',
'stylesheets',
'sidebar',

View File

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Constructor(DOMString type, optional MozContactChangeEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
[Constructor(DOMString type, optional MozContactChangeEventInit eventInitDict)]
interface MozContactChangeEvent : Event
{
readonly attribute DOMString? contactID;

View File

@ -476,7 +476,6 @@ WEBIDL_FILES += [
'ElementReplaceEvent.webidl',
'HashChangeEvent.webidl',
'MozApplicationEvent.webidl',
'MozContactChangeEvent.webidl',
'MozMmsEvent.webidl',
'MozSettingsEvent.webidl',
'MozSmsEvent.webidl',
@ -546,6 +545,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'DeviceProximityEvent.webidl',
'ErrorEvent.webidl',
'MediaStreamEvent.webidl',
'MozContactChangeEvent.webidl',
'MozInterAppMessageEvent.webidl',
'RTCDataChannelEvent.webidl',
'RTCPeerConnectionIceEvent.webidl',

View File

@ -132,9 +132,9 @@ JavaScriptChild::fail(JSContext *cx, ReturnStatus *rs)
return true;
}
if (!toVariant(cx, exn, &rs->get_ReturnException().exn()))
return true;
// If this fails, we still don't want to exit. Just return an invalid
// exception.
(void) toVariant(cx, exn, &rs->get_ReturnException().exn());
return true;
}
@ -377,7 +377,7 @@ JavaScriptChild::AnswerGet(const ObjectId &objId, const ObjectId &receiverId, co
if (!convertGeckoStringToId(cx, id, &internedId))
return fail(cx, rs);
JS::Rooted<JS::Value> val(cx);
JS::RootedValue val(cx);
if (!JS_ForwardGetPropertyTo(cx, obj, internedId, receiver, &val))
return fail(cx, rs);
@ -537,7 +537,7 @@ JavaScriptChild::AnswerCall(const ObjectId &objId, const nsTArray<JSParam> &argv
// treat this as the outparam never having been set.
for (size_t i = 0; i < vals.length(); i++) {
JSVariant variant;
if (!toVariant(cx, vals[i], &variant))
if (!toVariant(cx, vals.handleAt(i), &variant))
return fail(cx, rs);
outparams->ReplaceElementAt(i, JSParam(variant));
}

View File

@ -152,7 +152,7 @@ JavaScriptShared::convertGeckoStringToId(JSContext *cx, const nsString &from, JS
}
bool
JavaScriptShared::toVariant(JSContext *cx, jsval from, JSVariant *to)
JavaScriptShared::toVariant(JSContext *cx, JS::HandleValue from, JSVariant *to)
{
switch (JS_TypeOfValue(cx, from)) {
case JSTYPE_VOID:

View File

@ -91,7 +91,7 @@ class JavaScriptShared
bool Wrap(JSContext *cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows);
protected:
bool toVariant(JSContext *cx, jsval from, JSVariant *to);
bool toVariant(JSContext *cx, JS::HandleValue from, JSVariant *to);
bool toValue(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);
bool fromDescriptor(JSContext *cx, JS::Handle<JSPropertyDescriptor> desc, PPropertyDescriptor *out);
bool toDescriptor(JSContext *cx, const PPropertyDescriptor &in,

View File

@ -319,46 +319,6 @@ const Class js::NumericTypeClasses[ScalarTypeRepresentation::TYPE_MAX] = {
JS_FOR_EACH_SCALAR_TYPE_REPR(BINARYDATA_NUMERIC_CLASSES)
};
template <typename Domain, typename Input>
static bool
InRange(Input x)
{
return std::numeric_limits<Domain>::min() <= x &&
x <= std::numeric_limits<Domain>::max();
}
template <>
bool
InRange<float, int>(int x)
{
return -std::numeric_limits<float>::max() <= x &&
x <= std::numeric_limits<float>::max();
}
template <>
bool
InRange<double, int>(int x)
{
return -std::numeric_limits<double>::max() <= x &&
x <= std::numeric_limits<double>::max();
}
template <>
bool
InRange<float, double>(double x)
{
return -std::numeric_limits<float>::max() <= x &&
x <= std::numeric_limits<float>::max();
}
template <>
bool
InRange<double, double>(double x)
{
return -std::numeric_limits<double>::max() <= x &&
x <= std::numeric_limits<double>::max();
}
#define BINARYDATA_TYPE_TO_CLASS(constant_, type_, name_) \
template <> \
const Class * \

View File

@ -197,7 +197,7 @@ parser.add_argument('--source', metavar='SOURCE', type=str, nargs='?',
help='source code to analyze')
parser.add_argument('--upto', metavar='UPTO', type=str, nargs='?',
help='last step to execute')
parser.add_argument('--jobs', '-j', default=4, metavar='JOBS', type=int,
parser.add_argument('--jobs', '-j', default=None, metavar='JOBS', type=int,
help='number of simultaneous analyzeRoots.js jobs')
parser.add_argument('--list', const=True, nargs='?', type=bool,
help='display available steps')

View File

@ -556,7 +556,10 @@ for (var nameIndex = start; nameIndex <= end; nameIndex++) {
var name = xdb.read_key(nameIndex);
var functionName = name.readString();
var data = xdb.read_entry(name);
functionBodies = JSON.parse(data.readString());
xdb.free_string(name);
var json = data.readString();
xdb.free_string(data);
functionBodies = JSON.parse(json);
for (var body of functionBodies)
body.suppressed = [];
@ -565,7 +568,4 @@ for (var nameIndex = start; nameIndex <= end; nameIndex++) {
pbody.suppressed[id] = true;
}
processBodies(functionName);
xdb.free_string(name);
xdb.free_string(data);
}

View File

@ -24,6 +24,7 @@
# and the reports will only reflect the changes since the earlier run.
use strict;
use warnings;
use IO::Handle;
use File::Basename qw(dirname);
use Getopt::Long;
@ -193,7 +194,7 @@ sub get_manager_address
my $log_data = `cat $log_file`;
my ($port) = $log_data =~ /Listening on ([\.\:0-9]*)/
or die "no manager found";
print OUT "Connecting to manager on port $port\n";
print OUT "Connecting to manager on port $port\n" unless $suppress_logs;
print "Connecting to manager on port $port.\n";
return $1;
}
@ -310,7 +311,7 @@ sub run_pass
# collate the worker's output into a single file. make this asynchronous
# so we can wait a bit and make sure we get all worker output.
defined(my $pid = fork) or die;
defined($pid = fork) or die;
if (!$pid) {
sleep(20);

View File

@ -94,7 +94,7 @@ PushStatementPC(ParseContext<ParseHandler> *pc, StmtInfoPC *stmt, StmtType type)
template <>
bool
ParseContext<FullParseHandler>::define(TokenStream &ts,
PropertyName *name, ParseNode *pn, Definition::Kind kind)
HandlePropertyName name, ParseNode *pn, Definition::Kind kind)
{
JS_ASSERT(!pn->isUsed());
JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
@ -186,7 +186,7 @@ ParseContext<FullParseHandler>::define(TokenStream &ts,
template <>
bool
ParseContext<SyntaxParseHandler>::define(TokenStream &ts, PropertyName *name, Node pn,
ParseContext<SyntaxParseHandler>::define(TokenStream &ts, HandlePropertyName name, Node pn,
Definition::Kind kind)
{
JS_ASSERT(!decls_.lookupFirst(name));

View File

@ -167,7 +167,7 @@ struct ParseContext : public GenericParseContext
* 'pn' if they are in the scope of 'pn'.
* + Pre-existing placeholders in the scope of 'pn' have been removed.
*/
bool define(TokenStream &ts, PropertyName *name, Node pn, Definition::Kind);
bool define(TokenStream &ts, HandlePropertyName name, Node pn, Definition::Kind);
/*
* Let definitions may shadow same-named definitions in enclosing scopes.

View File

@ -6152,7 +6152,8 @@ CodeGenerator::addGetElementCache(LInstruction *ins, Register obj, ConstantOrReg
{
switch (gen->info().executionMode()) {
case SequentialExecution: {
GetElementIC cache(obj, index, output, monitoredResult);
RegisterSet liveRegs = ins->safepoint()->liveRegs();
GetElementIC cache(liveRegs, obj, index, output, monitoredResult);
return addCache(ins, allocateCache(cache));
}
case ParallelExecution: {

View File

@ -840,6 +840,7 @@ EmitGetterCall(JSContext *cx, MacroAssembler &masm,
Register scratchReg, TypedOrValueRegister output,
void *returnAddr)
{
JS_ASSERT(output.hasValue());
// saveLive()
MacroAssembler::AfterICSaveLive aic = masm.icSaveLive(liveRegs);
@ -983,20 +984,24 @@ static bool
GenerateCallGetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
IonCache::StubAttacher &attacher, JSObject *obj, PropertyName *name,
JSObject *holder, HandleShape shape, RegisterSet &liveRegs, Register object,
TypedOrValueRegister output, void *returnAddr)
TypedOrValueRegister output, void *returnAddr, Label *failures = NULL)
{
JS_ASSERT(obj->isNative());
// Initial shape check.
Label stubFailure;
masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()), &stubFailure);
JS_ASSERT(output.hasValue());
// Use the passed in label if there was one. Otherwise, we'll have to make our own.
Label stubFailure;
failures = failures ? failures : &stubFailure;
// Initial shape check.
masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()), failures);
Register scratchReg = output.valueReg().scratchReg();
// Note: this may clobber the object register if it's used as scratch.
if (obj != holder)
GeneratePrototypeGuards(cx, ion, masm, obj, holder, object, scratchReg, &stubFailure);
GeneratePrototypeGuards(cx, ion, masm, obj, holder, object, scratchReg, failures);
// Guard on the holder's shape.
Register holderReg = scratchReg;
@ -1004,7 +1009,7 @@ GenerateCallGetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
masm.branchPtr(Assembler::NotEqual,
Address(holderReg, JSObject::offsetOfShape()),
ImmGCPtr(holder->lastProperty()),
&stubFailure);
failures);
// Now we're good to go to invoke the native call.
if (!EmitGetterCall(cx, masm, attacher, obj, holder, shape, liveRegs, object,
@ -1015,7 +1020,7 @@ GenerateCallGetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
attacher.jumpRejoin(masm);
// Jump to next stub.
masm.bind(&stubFailure);
masm.bind(failures);
attacher.jumpNextStub(masm);
return true;
@ -1120,7 +1125,8 @@ template <class GetPropCache>
static GetPropertyIC::NativeGetPropCacheability
CanAttachNativeGetProp(typename GetPropCache::Context cx, const GetPropCache &cache,
HandleObject obj, HandlePropertyName name,
MutableHandleObject holder, MutableHandleShape shape)
MutableHandleObject holder, MutableHandleShape shape,
bool skipArrayLen = false)
{
if (!obj || !obj->isNative())
return GetPropertyIC::CanAttachNone;
@ -1146,7 +1152,10 @@ CanAttachNativeGetProp(typename GetPropCache::Context cx, const GetPropCache &ca
return GetPropertyIC::CanAttachReadSlot;
}
if (cx->names().length == name && cache.allowArrayLength(cx, obj) &&
// |length| is a non-configurable getter property on ArrayObjects. Any time this
// check would have passed, we can install a getter stub instead. Allow people to
// make that decision themselves with skipArrayLen
if (!skipArrayLen && cx->names().length == name && cache.allowArrayLength(cx, obj) &&
IsCacheableArrayLength(cx, obj, name, cache.output()))
{
// The array length property is non-configurable, which means both that
@ -1156,6 +1165,9 @@ CanAttachNativeGetProp(typename GetPropCache::Context cx, const GetPropCache &ca
return GetPropertyIC::CanAttachArrayLength;
}
// IonBuilder guarantees that it's impossible to generate a GetPropertyIC with
// allowGetters() true and cache.output().hasValue() false. If this isn't true,
// we will quickly assert during stub generation.
if (cache.allowGetters() &&
(IsCacheableGetPropCallNative(obj, holder, shape) ||
IsCacheableGetPropCallPropertyOp(obj, holder, shape)))
@ -1418,18 +1430,23 @@ GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, Handle
JS_ASSERT(canAttachStub());
JS_ASSERT(!*emitted);
JS_ASSERT(IsCacheableDOMProxy(obj));
JS_ASSERT(output().hasValue());
RootedObject checkObj(cx, obj->getTaggedProto().toObjectOrNull());
RootedObject holder(cx);
RootedShape shape(cx);
NativeGetPropCacheability canCache =
CanAttachNativeGetProp(cx, *this, checkObj, name, &holder, &shape);
CanAttachNativeGetProp(cx, *this, checkObj, name, &holder, &shape,
/* skipArrayLen = */true);
JS_ASSERT(canCache != CanAttachArrayLength);
if (canCache == CanAttachNone)
return true;
// Make sure we observe our invariants if we're gonna deoptimize.
if (!holder && (idempotent() || !output().hasValue()))
return true;
*emitted = true;
if (resetNeeded) {
@ -1479,7 +1496,8 @@ GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, Handle
// EmitGetterCall() expects |obj| to be the object the property is
// on to do some checks. Since we actually looked at checkObj, and
// no extra guards will be generated, we can just pass that instead.
JS_ASSERT_IF(canCache != CanAttachCallGetter, canCache == CanAttachArrayLength);
JS_ASSERT(canCache == CanAttachCallGetter);
JS_ASSERT(!idempotent());
if (!EmitGetterCall(cx, masm, attacher, checkObj, holder, shape, liveRegs_,
object(), scratchReg, output(), returnAddr))
{
@ -1489,6 +1507,7 @@ GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, Handle
} else {
// Property was not found on the prototype chain. Deoptimize down to
// proxy get call
JS_ASSERT(!idempotent());
if (!EmitCallProxyGet(cx, masm, attacher, name, liveRegs_, object(), output(),
returnAddr))
{
@ -1514,9 +1533,6 @@ GetPropertyIC::tryAttachProxy(JSContext *cx, IonScript *ion, HandleObject obj,
if (!obj->is<ProxyObject>())
return true;
if (!output().hasValue())
return true;
// Skim off DOM proxies.
if (IsCacheableDOMProxy(obj)) {
RootedId id(cx, NameToId(name));
@ -1560,6 +1576,9 @@ GetPropertyIC::tryAttachGenericProxy(JSContext *cx, IonScript *ion, HandleObject
if (hasGenericProxyStub())
return true;
if (idempotent() || !output().hasValue())
return true;
*emitted = true;
Label failures;
@ -2950,7 +2969,8 @@ GetElementIC::canAttachGetProp(JSObject *obj, const Value &idval, jsid id)
bool
GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj,
const Value &idval, HandlePropertyName name)
const Value &idval, HandlePropertyName name,
void *returnAddr)
{
JS_ASSERT(index().reg().hasValue());
@ -2958,9 +2978,14 @@ GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj,
RootedShape shape(cx);
GetPropertyIC::NativeGetPropCacheability canCache =
CanAttachNativeGetProp(cx, *this, obj, name, &holder, &shape);
CanAttachNativeGetProp(cx, *this, obj, name, &holder, &shape,
/* skipArrayLen =*/true);
if (canCache != GetPropertyIC::CanAttachReadSlot) {
bool cacheable = canCache == GetPropertyIC::CanAttachReadSlot ||
(canCache == GetPropertyIC::CanAttachCallGetter &&
output().hasValue());
if (!cacheable) {
IonSpew(IonSpew_InlineCaches, "GETELEM uncacheable property");
return true;
}
@ -2975,8 +3000,19 @@ GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj,
masm.branchTestValue(Assembler::NotEqual, val, idval, &failures);
RepatchStubAppender attacher(*this);
GenerateReadSlot(cx, ion, masm, attacher, obj, holder, shape, object(), output(),
&failures);
if (canCache == GetPropertyIC::CanAttachReadSlot) {
GenerateReadSlot(cx, ion, masm, attacher, obj, holder, shape, object(), output(),
&failures);
} else {
JS_ASSERT(canCache == GetPropertyIC::CanAttachCallGetter);
// Set the frame for bailout safety of the OOL call.
masm.setFramePushed(ion->frameSize());
if (!GenerateCallGetter(cx, ion, masm, attacher, obj, name, holder, shape, liveRegs_,
object(), output(), returnAddr, &failures))
{
return false;
}
}
return linkAndAttachStub(cx, masm, attacher, ion, "property");
}
@ -3301,7 +3337,8 @@ bool
GetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
HandleValue idval, MutableHandleValue res)
{
IonScript *ion = GetTopIonJSScript(cx)->ionScript();
void *returnAddr;
IonScript *ion = GetTopIonJSScript(cx, &returnAddr)->ionScript();
GetElementIC &cache = ion->getCache(cacheIndex).toGetElement();
RootedScript script(cx);
jsbytecode *pc;
@ -3338,7 +3375,7 @@ GetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
}
if (!attachedStub && cache.monitoredResult() && canAttachGetProp(obj, idval, id)) {
RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
if (!cache.attachGetProp(cx, ion, obj, idval, name))
if (!cache.attachGetProp(cx, ion, obj, idval, name, returnAddr))
return false;
attachedStub = true;
}

View File

@ -705,6 +705,8 @@ class SetPropertyIC : public RepatchIonCache
class GetElementIC : public RepatchIonCache
{
protected:
RegisterSet liveRegs_;
Register object_;
ConstantOrRegister index_;
TypedOrValueRegister output_;
@ -719,9 +721,10 @@ class GetElementIC : public RepatchIonCache
static const size_t MAX_FAILED_UPDATES;
public:
GetElementIC(Register object, ConstantOrRegister index,
GetElementIC(RegisterSet liveRegs, Register object, ConstantOrRegister index,
TypedOrValueRegister output, bool monitoredResult)
: object_(object),
: liveRegs_(liveRegs),
object_(object),
index_(index),
output_(output),
monitoredResult_(monitoredResult),
@ -761,7 +764,7 @@ class GetElementIC : public RepatchIonCache
// Helpers for CanAttachNativeGetProp
typedef JSContext * Context;
bool allowGetters() const { return false; }
bool allowGetters() const { JS_ASSERT(!idempotent()); return true; }
bool allowArrayLength(Context, HandleObject) const { return false; }
bool canMonitorSingletonUndefinedSlot(HandleObject holder, HandleShape shape) const {
return monitoredResult();
@ -772,7 +775,8 @@ class GetElementIC : public RepatchIonCache
static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval,
TypedOrValueRegister output);
bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval, HandlePropertyName name);
bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval,
HandlePropertyName name, void *returnAddr);
bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
const Value &idval);

View File

@ -616,6 +616,45 @@ JS_IsBuiltinFunctionConstructor(JSFunction *fun)
enum InitState { Uninitialized, Running, ShutDown };
static InitState jsInitState = Uninitialized;
#ifdef DEBUG
static void
CheckMessageNumbering()
{
// Assert that the numbers associated with the error names in js.msg are
// monotonically increasing. It's not a compile-time check, but it's
// better than nothing.
int errorNumber = 0;
# define MSG_DEF(name, number, count, exception, format) \
JS_ASSERT(name == errorNumber++);
# include "js.msg"
# undef MSG_DEF
}
static unsigned
MessageParameterCount(const char *format)
{
unsigned numfmtspecs = 0;
for (const char *fmt = format; *fmt != '\0'; fmt++) {
if (*fmt == '{' && isdigit(fmt[1]))
++numfmtspecs;
}
return numfmtspecs;
}
static void
CheckMessageParameterCounts()
{
// Assert that each message format has the correct number of braced
// parameters.
# define MSG_DEF(name, number, count, exception, format) \
JS_BEGIN_MACRO \
JS_ASSERT(MessageParameterCount(format) == count); \
JS_END_MACRO;
# include "js.msg"
# undef MSG_DEF
}
#endif /* DEBUG */
JS_PUBLIC_API(bool)
JS_Init(void)
{
@ -626,29 +665,9 @@ JS_Init(void)
"how do we have live runtimes before JS_Init?");
#ifdef DEBUG
// Assert that the numbers associated with the error names in js.msg are
// monotonically increasing. It's not a compile-time check, but it's
// better than nothing.
int errorNumber = 0;
#define MSG_DEF(name, number, count, exception, format) \
JS_ASSERT(name == errorNumber++);
#include "js.msg"
#undef MSG_DEF
// Assert that each message format has the correct number of braced
// parameters.
#define MSG_DEF(name, number, count, exception, format) \
JS_BEGIN_MACRO \
unsigned numfmtspecs = 0; \
for (const char *fmt = format; *fmt != '\0'; fmt++) { \
if (*fmt == '{' && isdigit(fmt[1])) \
++numfmtspecs; \
} \
JS_ASSERT(count == numfmtspecs); \
JS_END_MACRO;
#include "js.msg"
#undef MSG_DEF
#endif /* DEBUG */
CheckMessageNumbering();
CheckMessageParameterCounts();
#endif
using js::TlsPerThreadData;
if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init())

View File

@ -1086,14 +1086,14 @@ ArrayJoin(JSContext *cx, CallArgs &args)
// Steps 4 and 5
RootedString sepstr(cx, nullptr);
JS::Anchor<JSString *> anchor(nullptr);
const jschar *sepchars;
size_t seplen;
if (!Locale && args.hasDefined(0)) {
sepstr = ToString<CanGC>(cx, args[0]);
if (!sepstr)
return false;
}
const jschar *sepchars;
size_t seplen;
if (sepstr) {
anchor = sepstr;
sepchars = sepstr->getChars(cx);
if (!sepchars)
return false;

View File

@ -3252,7 +3252,7 @@ proxy_createFunction(JSContext *cx, unsigned argc, Value *vp)
RootedObject call(cx, ValueToCallable(cx, vp[3], argc - 2));
if (!call)
return false;
JSObject *construct = nullptr;
RootedObject construct(cx, nullptr);
if (argc > 2) {
construct = ValueToCallable(cx, vp[4], argc - 3);
if (!construct)

View File

@ -593,6 +593,7 @@ js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChainArg, c
#ifdef DEBUG
if (thisv.isObject()) {
RootedObject thisObj(cx, &thisv.toObject());
AutoSuppressGC nogc(cx);
JS_ASSERT(GetOuterObject(cx, thisObj) == thisObj);
}
#endif

View File

@ -17,7 +17,6 @@ simple_events = [
'PopStateEvent',
'HashChangeEvent',
'CloseEvent',
'MozContactChangeEvent',
'DeviceOrientationEvent',
'MozApplicationEvent',
'SmartCardEvent',

View File

@ -749,7 +749,7 @@ TEST_F(TransportConduitTest, TestVideoConduitCodecAPI) {
int main(int argc, char **argv)
{
// This test can cause intermittent oranges on the builders
CHECK_ENVIRONMENT_FLAG("MOZ_WEBRTC_TESTS")
CHECK_ENVIRONMENT_FLAG("MOZ_WEBRTC_MEDIACONDUIT_TESTS")
test_utils = new MtransportTestUtils();
::testing::InitGoogleTest(&argc, argv);