Merge mozilla-central to mozilla-inbound

This commit is contained in:
Ed Morley 2013-03-20 11:47:15 +00:00
commit e2a4cc14b8
47 changed files with 512 additions and 1131 deletions

View File

@ -229,10 +229,11 @@ public:
// Return true if we can activate autoplay assuming enough data has arrived.
bool CanActivateAutoplay();
// Notify that enough data has arrived to start autoplaying.
// Notify that state has changed that might cause an autoplay element to
// start playing.
// If the element is 'autoplay' and is ready to play back (not paused,
// autoplay pref enabled, etc), it should start playing back.
virtual void NotifyAutoplayDataReady() MOZ_FINAL MOZ_OVERRIDE;
void CheckAutoplayDataReady();
// Check if the media element had crossorigin set when loading started
bool ShouldCheckAllowOrigin();

View File

@ -2215,9 +2215,7 @@ nsresult HTMLMediaElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
if (aNotify && aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::autoplay) {
StopSuspendingAfterFirstFrame();
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
NotifyAutoplayDataReady();
}
CheckAutoplayDataReady();
// This attribute can affect AddRemoveSelfReference
AddRemoveSelfReference();
UpdatePreloadAction();
@ -2467,8 +2465,7 @@ public:
mHaveCurrentData(false),
mBlocked(false),
mMutex("HTMLMediaElement::StreamListener"),
mPendingNotifyOutput(false),
mDidHaveCurrentData(false)
mPendingNotifyOutput(false)
{}
void Forget() { mElement = nullptr; }
@ -2535,21 +2532,12 @@ public:
NS_NewRunnableMethod(this, &StreamListener::DoNotifyFinished);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
}
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph,
bool aHasCurrentData)
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph)
{
MutexAutoLock lock(mMutex);
if (mDidHaveCurrentData == aHasCurrentData)
return;
mDidHaveCurrentData = aHasCurrentData;
// Ignore the case where aHasCurrentData is false. If aHasCurrentData
// changes from true to false, we don't worry about it. Video elements
// preserve the last played frame anyway.
if (aHasCurrentData) {
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &StreamListener::DoNotifyHaveCurrentData);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
}
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &StreamListener::DoNotifyHaveCurrentData);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
}
virtual void NotifyOutput(MediaStreamGraph* aGraph)
{
@ -2571,7 +2559,6 @@ private:
// mMutex protects the fields below; they can be accessed on any thread
Mutex mMutex;
bool mPendingNotifyOutput;
bool mDidHaveCurrentData;
};
void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
@ -2854,6 +2841,9 @@ void HTMLMediaElement::SeekCompleted()
void HTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended)
{
mDownloadSuspendedByCache = aIsSuspended;
// If this is an autoplay element, we may need to kick off its autoplaying
// now so we consume data and hopefully free up cache space.
CheckAutoplayDataReady();
}
void HTMLMediaElement::DownloadSuspended()
@ -2992,9 +2982,7 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
DispatchAsyncEvent(NS_LITERAL_STRING("canplay"));
}
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
NotifyAutoplayDataReady();
}
CheckAutoplayDataReady();
if (oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
@ -3010,14 +2998,20 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
bool HTMLMediaElement::CanActivateAutoplay()
{
// For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
// this element itself might be blocking the stream from making progress by
// being paused.
return mAutoplaying &&
mPaused &&
(mDownloadSuspendedByCache ||
(mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
(mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)) &&
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
mAutoplayEnabled &&
!IsEditable();
}
void HTMLMediaElement::NotifyAutoplayDataReady()
void HTMLMediaElement::CheckAutoplayDataReady()
{
if (CanActivateAutoplay()) {
mPaused = false;

View File

@ -48,6 +48,8 @@ public:
mEngine(aEngine),
mKind(aKind)
{
// AudioNodes are always producing data
mHasCurrentData = true;
}
~AudioNodeStream();

View File

@ -952,11 +952,6 @@ void MediaDecoder::NotifySuspendedStatusChanged()
bool suspended = mResource->IsSuspendedByCache(&activeStream);
if (mOwner) {
if (suspended) {
// If this is an autoplay element, we need to kick off its autoplaying
// now so we consume data and hopefully free up cache space.
mOwner->NotifyAutoplayDataReady();
}
mOwner->NotifySuspendedByCache(suspended);
UpdateReadyStateForData();
}

View File

@ -109,11 +109,6 @@ public:
// ongoing.
virtual void DownloadResumed(bool aForceNetworkLoading = false) = 0;
// Notify that enough data has arrived to start autoplaying.
// If the element is 'autoplay' and is ready to play back (not paused,
// autoplay pref enabled, etc), it should start playing back.
virtual void NotifyAutoplayDataReady() = 0;
// Called by the media decoder to indicate whether the media cache has
// suspended the channel.
virtual void NotifySuspendedByCache(bool aIsSuspended) = 0;

View File

@ -175,6 +175,9 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
}
aStream->mBuffer.AdvanceKnownTracksTime(aStream->mUpdateKnownTracksTime);
}
if (aStream->mBuffer.GetEnd() > 0) {
aStream->mHasCurrentData = true;
}
if (finished) {
FinishStream(aStream);
}
@ -659,10 +662,12 @@ MediaStreamGraphImpl::RecomputeBlockingAt(const nsTArray<MediaStream*>& aStreams
void
MediaStreamGraphImpl::NotifyHasCurrentData(MediaStream* aStream)
{
for (uint32_t j = 0; j < aStream->mListeners.Length(); ++j) {
MediaStreamListener* l = aStream->mListeners[j];
l->NotifyHasCurrentData(this,
GraphTimeToStreamTime(aStream, mCurrentTime) < aStream->mBuffer.GetEnd());
if (!aStream->mNotifiedHasCurrentData && aStream->mHasCurrentData) {
for (uint32_t j = 0; j < aStream->mListeners.Length(); ++j) {
MediaStreamListener* l = aStream->mListeners[j];
l->NotifyHasCurrentData(this);
}
aStream->mNotifiedHasCurrentData = true;
}
}
@ -1577,6 +1582,9 @@ MediaStream::AddListenerImpl(already_AddRefed<MediaStreamListener> aListener)
if (mNotifiedFinished) {
listener->NotifyFinished(GraphImpl());
}
if (mNotifiedHasCurrentData) {
listener->NotifyHasCurrentData(GraphImpl());
}
}
void

View File

@ -128,10 +128,12 @@ public:
virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) {}
/**
* Notify that the stream has (or does not have) data in each track
* for the stream's current time.
* Notify that the stream has data in each track
* for the stream's current time. Once this state becomes true, it will
* always be true since we block stream time from progressing to times where
* there isn't data in each track.
*/
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph, bool aHasCurrentData) {}
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph) {}
/**
* Notify that the stream output is advancing.
@ -268,6 +270,8 @@ public:
, mFinished(false)
, mNotifiedFinished(false)
, mNotifiedBlocked(false)
, mHasCurrentData(false)
, mNotifiedHasCurrentData(false)
, mWrapper(aWrapper)
, mMainThreadCurrentTime(0)
, mMainThreadFinished(false)
@ -421,6 +425,8 @@ public:
bool IsFinishedOnGraphThread() { return mFinished; }
void FinishOnGraphThread();
bool HasCurrentData() { return mHasCurrentData; }
protected:
virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime, GraphTime aBlockedTime)
{
@ -503,6 +509,17 @@ protected:
* indicated that the stream is blocked.
*/
bool mNotifiedBlocked;
/**
* True if some data can be present by this stream if/when it's unblocked.
* Set by the stream itself on the MediaStreamGraph thread. Only changes
* from false to true once a stream has data, since we won't
* unblock it until there's more data.
*/
bool mHasCurrentData;
/**
* True if mHasCurrentData is true and we've notified listeners.
*/
bool mNotifiedHasCurrentData;
// Temporary data for ordering streams by dependency graph
bool mHasBeenOrdered;

View File

@ -47,11 +47,15 @@ public:
mappedTracksWithMatchingInputTracks.AppendElement(false);
}
bool allFinished = true;
bool allHaveCurrentData = true;
for (uint32_t i = 0; i < mInputs.Length(); ++i) {
MediaStream* stream = mInputs[i]->GetSource();
if (!stream->IsFinishedOnGraphThread()) {
allFinished = false;
}
if (!stream->HasCurrentData()) {
allHaveCurrentData = false;
}
for (StreamBuffer::TrackIter tracks(stream->GetStreamBuffer());
!tracks.IsEnded(); tracks.Next()) {
bool found = false;
@ -97,6 +101,10 @@ public:
FinishOnGraphThread();
}
mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime(aTo));
if (allHaveCurrentData) {
// We can make progress if we're not blocked
mHasCurrentData = true;
}
}
protected:

View File

@ -14,6 +14,7 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
Cu.import("resource://gre/modules/ObjectWrapper.jsm");
XPCOMUtils.defineLazyGetter(Services, "DOMRequest", function() {
return Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci.nsIDOMRequestService);
@ -454,7 +455,8 @@ ContactManager.prototype = {
return contact;
});
if (DEBUG) debug("result: " + JSON.stringify(result));
Services.DOMRequest.fireSuccess(req.request, result);
Services.DOMRequest.fireSuccess(req.request,
ObjectWrapper.wrap(result, this._window));
} else {
if (DEBUG) debug("no request stored!" + msg.requestID);
}

View File

@ -20,6 +20,8 @@ function testImportSimContacts() {
request.onsuccess = function onsuccess() {
let simContacts = request.result;
is(Array.isArray(simContacts), true);
// These SIM contacts are harded in external/qemu/telephony/sim_card.c
is(simContacts[0].name, "Mozilla");
is(simContacts[0].tel[0].value, "15555218201");

View File

@ -26,7 +26,7 @@ interface nsIDOMMozMmsMessage : nsISupports
/**
* Should be "not-downloaded", "received", "sending", "sent" or "error".
*/
readonly attribute DOMString state;
readonly attribute DOMString delivery;
[implicit_jscontext]
readonly attribute jsval deliveryStatus; // DOMString[]

View File

@ -16,10 +16,6 @@ interface nsIDOMMozSmsMessage : nsISupports
/**
* Should be "received", "sending", "sent" or "error".
*
* TODO Bug 850530 Please see the IDL proposal at Bug 760065.
* We need to s/delivery/state in nsIDOMMozSmsMessage, which sounds
* a better name and can be consistent with nsIDOMMozMmsMessage.
*/
readonly attribute DOMString delivery;

View File

@ -29,7 +29,7 @@ interface nsIMobileMessageService : nsISupports
[implicit_jscontext]
nsIDOMMozMmsMessage createMmsMessage(in long id,
in DOMString state,
in DOMString delivery,
in jsval deliveryStatus,
in DOMString sender,
in jsval receivers,

View File

@ -31,7 +31,7 @@ NS_IMPL_ADDREF(MmsMessage)
NS_IMPL_RELEASE(MmsMessage)
MmsMessage::MmsMessage(int32_t aId,
DeliveryState aState,
DeliveryState aDelivery,
const nsTArray<DeliveryStatus>& aDeliveryStatus,
const nsAString& aSender,
const nsTArray<nsString>& aReceivers,
@ -41,7 +41,7 @@ MmsMessage::MmsMessage(int32_t aId,
const nsAString& aSmil,
const nsTArray<MmsAttachment>& aAttachments)
: mId(aId),
mState(aState),
mDelivery(aDelivery),
mDeliveryStatus(aDeliveryStatus),
mSender(aSender),
mReceivers(aReceivers),
@ -55,7 +55,7 @@ MmsMessage::MmsMessage(int32_t aId,
/* static */ nsresult
MmsMessage::Create(int32_t aId,
const nsAString& aState,
const nsAString& aDelivery,
const JS::Value& aDeliveryStatus,
const nsAString& aSender,
const JS::Value& aReceivers,
@ -69,18 +69,18 @@ MmsMessage::Create(int32_t aId,
{
*aMessage = nullptr;
// Set |state|.
DeliveryState state;
if (aState.Equals(DELIVERY_SENT)) {
state = eDeliveryState_Sent;
} else if (aState.Equals(DELIVERY_RECEIVED)) {
state = eDeliveryState_Received;
} else if (aState.Equals(DELIVERY_SENDING)) {
state = eDeliveryState_Sending;
} else if (aState.Equals(DELIVERY_NOT_DOWNLOADED)) {
state = eDeliveryState_NotDownloaded;
} else if (aState.Equals(DELIVERY_ERROR)) {
state = eDeliveryState_Error;
// Set |delivery|.
DeliveryState delivery;
if (aDelivery.Equals(DELIVERY_SENT)) {
delivery = eDeliveryState_Sent;
} else if (aDelivery.Equals(DELIVERY_RECEIVED)) {
delivery = eDeliveryState_Received;
} else if (aDelivery.Equals(DELIVERY_SENDING)) {
delivery = eDeliveryState_Sending;
} else if (aDelivery.Equals(DELIVERY_NOT_DOWNLOADED)) {
delivery = eDeliveryState_NotDownloaded;
} else if (aDelivery.Equals(DELIVERY_ERROR)) {
delivery = eDeliveryState_Error;
} else {
return NS_ERROR_INVALID_ARG;
}
@ -193,7 +193,7 @@ MmsMessage::Create(int32_t aId,
}
nsCOMPtr<nsIDOMMozMmsMessage> message = new MmsMessage(aId,
state,
delivery,
deliveryStatus,
aSender,
receivers,
@ -221,23 +221,23 @@ MmsMessage::GetId(int32_t* aId)
}
NS_IMETHODIMP
MmsMessage::GetState(nsAString& aState)
MmsMessage::GetDelivery(nsAString& aDelivery)
{
switch (mState) {
switch (mDelivery) {
case eDeliveryState_Received:
aState = DELIVERY_RECEIVED;
aDelivery = DELIVERY_RECEIVED;
break;
case eDeliveryState_Sending:
aState = DELIVERY_SENDING;
aDelivery = DELIVERY_SENDING;
break;
case eDeliveryState_Sent:
aState = DELIVERY_SENT;
aDelivery = DELIVERY_SENT;
break;
case eDeliveryState_Error:
aState = DELIVERY_ERROR;
aDelivery = DELIVERY_ERROR;
break;
case eDeliveryState_NotDownloaded:
aState = DELIVERY_NOT_DOWNLOADED;
aDelivery = DELIVERY_NOT_DOWNLOADED;
break;
case eDeliveryState_Unknown:
case eDeliveryState_EndGuard:
@ -252,8 +252,8 @@ MmsMessage::GetState(nsAString& aState)
NS_IMETHODIMP
MmsMessage::GetDeliveryStatus(JSContext* aCx, JS::Value* aDeliveryStatus)
{
// TODO Bug 850525 It would be better to depend on the state of MmsMessage
// to return a more correct value. Ex, when .state = 'received', we should
// TODO Bug 850525 It'd be better to depend on the delivery of MmsMessage
// to return a more correct value. Ex, if .delivery = 'received', we should
// also make .deliveryStatus = null, since the .deliveryStatus is useless.
uint32_t length = mDeliveryStatus.Length();
if (length == 0) {

View File

@ -22,8 +22,8 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMMOZMMSMESSAGE
MmsMessage(int32_t aId,
mobilemessage::DeliveryState aState,
MmsMessage(int32_t aId,
mobilemessage::DeliveryState aDelivery,
const nsTArray<mobilemessage::DeliveryStatus>& aDeliveryStatus,
const nsAString& aSender,
const nsTArray<nsString>& aReceivers,
@ -34,7 +34,7 @@ public:
const nsTArray<idl::MmsAttachment>& aAttachments);
static nsresult Create(int32_t aId,
const nsAString& aState,
const nsAString& aDelivery,
const JS::Value& aDeliveryStatus,
const nsAString& aSender,
const JS::Value& aReceivers,
@ -49,7 +49,7 @@ public:
private:
int32_t mId;
mobilemessage::DeliveryState mState;
mobilemessage::DeliveryState mDelivery;
nsTArray<mobilemessage::DeliveryStatus> mDeliveryStatus;
nsString mSender;
nsTArray<nsString> mReceivers;

View File

@ -56,7 +56,7 @@ MobileMessageService::CreateSmsMessage(int32_t aId,
NS_IMETHODIMP
MobileMessageService::CreateMmsMessage(int32_t aId,
const nsAString& aState,
const nsAString& aDelivery,
const JS::Value& aDeliveryStatus,
const nsAString& aSender,
const JS::Value& aReceivers,
@ -69,7 +69,7 @@ MobileMessageService::CreateMmsMessage(int32_t aId,
nsIDOMMozMmsMessage** aMessage)
{
return MmsMessage::Create(aId,
aState,
aDelivery,
aDeliveryStatus,
aSender,
aReceivers,

View File

@ -1153,9 +1153,10 @@ BasicShadowLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
} else if (mShadowTarget) {
if (mWidget) {
if (CompositorChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
nsRefPtr<gfxASurface> target = mShadowTarget->OriginalSurface();
nsIntRect bounds;
mWidget->GetBounds(bounds);
SurfaceDescriptor inSnapshot, snapshot;
if (AllocBuffer(target->GetSize(), target->GetContentType(),
if (AllocBuffer(bounds.Size(), gfxASurface::CONTENT_COLOR_ALPHA,
&inSnapshot) &&
// The compositor will usually reuse |snapshot| and return
// it through |outSnapshot|, but if it doesn't, it's
@ -1164,8 +1165,6 @@ BasicShadowLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
AutoOpenSurface opener(OPEN_READ_ONLY, snapshot);
gfxASurface* source = opener.Get();
gfxContextAutoSaveRestore restore(mShadowTarget);
mShadowTarget->SetOperator(gfxContext::OPERATOR_OVER);
mShadowTarget->DrawSurface(source, source->GetSize());
}
if (IsSurfaceDescriptorValid(snapshot)) {

View File

@ -85,6 +85,20 @@ struct TypeInferenceSizes
}
};
// Data for tracking JIT-code memory usage.
struct CodeSizes
{
size_t jaeger;
size_t ion;
size_t asmJS;
size_t baseline;
size_t regexp;
size_t other;
size_t unused;
CodeSizes() { memset(this, 0, sizeof(CodeSizes)); }
};
// Holds data about a huge string (one which uses more HugeStringInfo::MinSize
// bytes of memory), so we can report it individually.
struct HugeStringInfo
@ -118,17 +132,14 @@ struct RuntimeSizes
size_t contexts;
size_t dtoa;
size_t temporary;
size_t jaegerCode;
size_t ionCode;
size_t asmJSCode;
size_t regexpCode;
size_t unusedCode;
size_t regexpData;
size_t stack;
size_t gcMarker;
size_t mathCache;
size_t scriptData;
size_t scriptSources;
CodeSizes code;
};
struct ZoneStats

View File

@ -118,6 +118,24 @@ class HandleBase {};
template <typename T>
class MutableHandleBase {};
/*
* js::NullPtr acts like a NULL pointer in contexts that require a Handle.
*
* Handle provides an implicit constructor for js::NullPtr so that, given:
* foo(Handle<JSObject*> h);
* callers can simply write:
* foo(js::NullPtr());
* which avoids creating a Rooted<JSObject*> just to pass NULL.
*
* This is the SpiderMonkey internal variant. js::NullPtr should be used in
* preference to JS::NullPtr to avoid the GOT access required for JS_PUBLIC_API
* symbols.
*/
struct NullPtr
{
static void * const constNullValue;
};
} /* namespace js */
namespace JS {
@ -136,13 +154,15 @@ CheckStackRoots(JSContext *cx);
#endif
/*
* Handle provides an implicit constructor for NullPtr so that, given:
* JS::NullPtr acts like a NULL pointer in contexts that require a Handle.
*
* Handle provides an implicit constructor for JS::NullPtr so that, given:
* foo(Handle<JSObject*> h);
* callers can simply write:
* foo(NullPtr());
* foo(JS::NullPtr());
* which avoids creating a Rooted<JSObject*> just to pass NULL.
*/
struct NullPtr
struct JS_PUBLIC_API(NullPtr)
{
static void * const constNullValue;
};
@ -170,9 +190,15 @@ class Handle : public js::HandleBase<T>
}
/* Create a handle for a NULL pointer. */
Handle(NullPtr) {
Handle(js::NullPtr) {
typedef typename js::tl::StaticAssert<mozilla::IsPointer<T>::value>::result _;
ptr = reinterpret_cast<const T *>(&NullPtr::constNullValue);
ptr = reinterpret_cast<const T *>(&js::NullPtr::constNullValue);
}
/* Create a handle for a NULL pointer. */
Handle(JS::NullPtr) {
typedef typename js::tl::StaticAssert<mozilla::IsPointer<T>::value>::result _;
ptr = reinterpret_cast<const T *>(&JS::NullPtr::constNullValue);
}
Handle(MutableHandle<T> handle) {
@ -353,7 +379,7 @@ class InternalHandle<T*>
* fromMarkedLocation().
*/
InternalHandle(T *field)
: holder(reinterpret_cast<void * const *>(&JS::NullPtr::constNullValue)),
: holder(reinterpret_cast<void * const *>(&js::NullPtr::constNullValue)),
offset(uintptr_t(field))
{}
};

View File

@ -965,17 +965,20 @@ selfhosting_srcs := \
selfhosted_out_h_deps := \
$(selfhosting_srcs) \
$(srcdir)/js.msg \
$(srcdir)/builtin/macros.py \
$(srcdir)/builtin/js2c.py \
$(srcdir)/builtin/embedjs.py
$(srcdir)/builtin/embedjs.py \
$(NULL)
ifeq ($(MOZ_DEBUG),1)
selfhosting_embed_flags += -d
selfhosting_defines += -DDEBUG
endif
ifneq (,$(MOZ_ZLIB_LIBS)$(MOZ_GLUE_LDFLAGS))
selfhosting_defines += -DUSE_ZLIB
endif
selfhosted.out.h: $(selfhosted_out_h_deps)
$(PYTHON) $(srcdir)/builtin/embedjs.py $(selfhosting_embed_flags) $@ \
$(srcdir)/js.msg $(srcdir)/builtin/macros.py $(selfhosting_srcs)
$(PYTHON) $(srcdir)/builtin/embedjs.py $(selfhosting_defines) \
-p '$(CPP)' -m $(srcdir)/js.msg -o $@ $(selfhosting_srcs)
###############################################
# BEGIN kludges for the Nitro assembler

View File

@ -1,4 +1,6 @@
/*
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99:
*
* Copyright (C) 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -25,6 +27,8 @@
#include "ExecutableAllocator.h"
#include "js/MemoryMetrics.h"
#if ENABLE_ASSEMBLER
#include "prmjtime.h"
@ -40,23 +44,25 @@ ExecutablePool::~ExecutablePool()
}
void
ExecutableAllocator::sizeOfCode(size_t *jaeger, size_t *ion, size_t *asmJS, size_t *regexp, size_t *unused) const
ExecutableAllocator::sizeOfCode(JS::CodeSizes *sizes) const
{
*jaeger = 0;
*ion = 0;
*asmJS = 0;
*regexp = 0;
*unused = 0;
*sizes = JS::CodeSizes();
if (m_pools.initialized()) {
for (ExecPoolHashSet::Range r = m_pools.all(); !r.empty(); r.popFront()) {
ExecutablePool* pool = r.front();
*jaeger += pool->m_jaegerCodeBytes;
*ion += pool->m_ionCodeBytes;
*asmJS += pool->m_asmJSCodeBytes;
*regexp += pool->m_regexpCodeBytes;
*unused += pool->m_allocation.size - pool->m_jaegerCodeBytes - pool->m_ionCodeBytes
- pool->m_asmJSCodeBytes - pool->m_regexpCodeBytes;
sizes->jaeger += pool->m_jaegerCodeBytes;
sizes->ion += pool->m_ionCodeBytes;
sizes->baseline += pool->m_baselineCodeBytes;
sizes->asmJS += pool->m_asmJSCodeBytes;
sizes->regexp += pool->m_regexpCodeBytes;
sizes->other += pool->m_otherCodeBytes;
sizes->unused += pool->m_allocation.size - pool->m_jaegerCodeBytes
- pool->m_ionCodeBytes
- pool->m_baselineCodeBytes
- pool->m_asmJSCodeBytes
- pool->m_regexpCodeBytes
- pool->m_otherCodeBytes;
}
}
}

View File

@ -78,11 +78,15 @@ extern "C" void sync_instruction_memory(caddr_t v, u_int len);
//#define DEBUG_STRESS_JSC_ALLOCATOR
namespace JS {
struct CodeSizes;
}
namespace JSC {
class ExecutableAllocator;
enum CodeKind { JAEGER_CODE, ION_CODE, REGEXP_CODE, ASMJS_CODE };
enum CodeKind { JAEGER_CODE, ION_CODE, BASELINE_CODE, REGEXP_CODE, ASMJS_CODE, OTHER_CODE };
// These are reference-counted. A new one starts with a count of 1.
class ExecutablePool {
@ -108,8 +112,10 @@ private:
// Number of bytes currently used for Method and Regexp JIT code.
size_t m_jaegerCodeBytes;
size_t m_ionCodeBytes;
size_t m_baselineCodeBytes;
size_t m_asmJSCodeBytes;
size_t m_regexpCodeBytes;
size_t m_otherCodeBytes;
public:
// Flag for downstream use, whether to try to release references to this pool.
@ -130,7 +136,8 @@ public:
ExecutablePool(ExecutableAllocator* allocator, Allocation a)
: m_allocator(allocator), m_freePtr(a.pages), m_end(m_freePtr + a.size), m_allocation(a),
m_refCount(1), m_jaegerCodeBytes(0), m_ionCodeBytes(0), m_asmJSCodeBytes(0), m_regexpCodeBytes(0),
m_refCount(1), m_jaegerCodeBytes(0), m_ionCodeBytes(0), m_baselineCodeBytes(0),
m_asmJSCodeBytes(0), m_regexpCodeBytes(0), m_otherCodeBytes(0),
m_destroy(false), m_gcNumber(0)
{ }
@ -153,11 +160,13 @@ private:
m_freePtr += n;
switch (kind) {
case JAEGER_CODE: m_jaegerCodeBytes += n; break;
case ION_CODE: m_ionCodeBytes += n; break;
case ASMJS_CODE: m_asmJSCodeBytes += n; break;
case REGEXP_CODE: m_regexpCodeBytes += n; break;
default: JS_NOT_REACHED("bad code kind"); break;
case JAEGER_CODE: m_jaegerCodeBytes += n; break;
case ION_CODE: m_ionCodeBytes += n; break;
case BASELINE_CODE: m_baselineCodeBytes += n; break;
case ASMJS_CODE: m_asmJSCodeBytes += n; break;
case REGEXP_CODE: m_regexpCodeBytes += n; break;
case OTHER_CODE: m_otherCodeBytes += n; break;
default: JS_NOT_REACHED("bad code kind"); break;
}
return result;
}
@ -255,7 +264,7 @@ public:
m_pools.remove(m_pools.lookup(pool)); // this asserts if |pool| is not in m_pools
}
void sizeOfCode(size_t *jaeger, size_t *ion, size_t *asmJS, size_t *regexp, size_t *unused) const;
void sizeOfCode(JS::CodeSizes *sizes) const;
void setDestroyCallback(DestroyCallback destroyCallback) {
this->destroyCallback = destroyCallback;

View File

@ -4,6 +4,30 @@
// FIXME(bug 844882): Parallel array properties should not be exposed.
// The mode asserts options object.
#define TRY_PARALLEL(MODE) \
((!MODE || MODE.mode === "par"))
#define ASSERT_SEQUENTIAL_IS_OK(MODE) \
do { if (MODE) AssertSequentialIsOK(MODE) } while(false)
// Slice array: see ComputeAllSliceBounds()
#define SLICE_INFO(START, END) START, END, START, 0
#define SLICE_START(ID) ((ID << 2) + 0)
#define SLICE_END(ID) ((ID << 2) + 1)
#define SLICE_POS(ID) ((ID << 2) + 2)
// How many items at a time do we do recomp. for parallel execution.
// Note that filter currently assumes that this is no greater than 32
// in order to make use of a bitset.
#define CHUNK_SHIFT 5
#define CHUNK_SIZE 32
// Safe versions of ARRAY.push(ELEMENT)
#define ARRAY_PUSH(ARRAY, ELEMENT) \
callFunction(std_Array_push, ARRAY, ELEMENT);
#define ARRAY_SLICE(ARRAY, ELEMENT) \
callFunction(std_Array_slice, ARRAY, ELEMENT);
/**
* Determine the number of chunks of size CHUNK_SIZE;
* note that the final chunk may be smaller than CHUNK_SIZE.

View File

@ -23,6 +23,8 @@
JSMSG_EMPTY_ARRAY_REDUCE: false,
*/
/* Utility macros */
#define TO_UINT32(x) (x >>> 0)
/* cache built-in functions before applications can change them */
var std_isFinite = isFinite;
@ -138,4 +140,3 @@ function assert(b, info) {
if (!b)
AssertionFailed(info);
}

View File

@ -1,58 +1,166 @@
# 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/.
#
# ToCAsciiArray and ToCArray are from V8's js2c.py.
#
# Copyright 2012 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# This utility converts JS files containing self-hosted builtins into a C
# header file that can be embedded into SpiderMonkey.
#
# It expects error messages in the JS code to be referenced by their C enum
# keys as literals.
# It uses the C preprocessor to process its inputs.
from __future__ import with_statement
import re, sys, os, js2c, fileinput
import re, sys, os, fileinput, subprocess
import shlex
from optparse import OptionParser
def replaceErrorMsgs(source_files, messages_file, output_file):
messages = buildMessagesTable(messages_file)
# For cases where one key is a prefix of another, we need to check
# for the longer one first. Using a reverse-sorted key list ensures that.
message_keys = messages.keys()
message_keys.sort(reverse=True)
with open(output_file, 'w') as output:
if len(source_files) == 0:
return
for line in fileinput.input(source_files):
line = line if line[-1] == '\n' else line + '\n'
output.write(replaceMessages(line, messages, message_keys))
def ToCAsciiArray(lines):
result = []
for chr in lines:
value = ord(chr)
assert value < 128
result.append(str(value))
return ", ".join(result)
def buildMessagesTable(messages_file):
table = {}
pattern = re.compile(r"MSG_DEF\(([\w_]+),\s*(\d+)")
for line in fileinput.input(messages_file):
match = pattern.match(line)
if match:
table[match.group(1)] = match.group(2)
return table
def ToCArray(lines):
result = []
for chr in lines:
result.append(str(ord(chr)))
return ", ".join(result)
def replaceMessages(line, messages, message_keys):
if not 'JSMSG_' in line:
return line
for key in message_keys:
line = line.replace(key, messages[key])
return line
HEADER_TEMPLATE = """\
/* 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/. */
namespace js {
namespace selfhosted {
static const char data[] = { %(sources_data)s };
%(sources_declaration)s
uint32_t GetCompressedSize() {
return %(compressed_total_length)i;
}
uint32_t GetRawScriptsSize() {
return %(raw_total_length)i;
}
} // selfhosted
} // js
"""
RAW_SOURCES_DECLARATION = """\
static const char *rawSources = reinterpret_cast<const char *>(data);
"""
COMPRESSED_SOURCES_DECLARATION = """\
static const unsigned char *compressedSources = reinterpret_cast<const unsigned char *>(data);
"""
def embed(cpp, msgs, sources, c_out, js_out, env):
# Clang seems to complain and not output anything if the extension of the
# input is not something it recognizes, so just fake a .h here.
tmp = 'selfhosted.js.h'
with open(tmp, 'wb') as output:
output.write('\n'.join([msgs] + ['#include "%(s)s"' % { 's': source } for source in sources]))
cmdline = cpp + ['-D%(k)s=%(v)s' % { 'k': k, 'v': env[k] } for k in env] + [tmp]
p = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
processed = ''
for line in p.stdout:
if not line.startswith('#'):
processed += line
os.remove(tmp)
with open(js_out, 'w') as output:
output.write(processed)
with open(c_out, 'w') as output:
if 'USE_ZLIB' in env:
import zlib
compressed = zlib.compress(processed)
data = ToCArray(compressed)
output.write(HEADER_TEMPLATE % {
'sources_data': data,
'sources_declaration': COMPRESSED_SOURCES_DECLARATION,
'compressed_total_length': len(compressed),
'raw_total_length': len(processed)
})
else:
data = ToCAsciiArray(processed)
output.write(HEADER_TEMPLATE % {
'sources_data': data,
'sources_declaration': RAW_SOURCES_DECLARATION,
'compressed_total_length': 0,
'raw_total_length': len(processed)
})
def process_msgs(cpp, msgs):
# Clang seems to complain and not output anything if the extension of the
# input is not something it recognizes, so just fake a .h here.
tmp = 'selfhosted.msg.h'
with open(tmp, 'wb') as output:
output.write("""\
#define hash #
#define id(x) x
#define hashify(x) id(hash)x
#define MSG_DEF(name, id, argc, ex, msg) hashify(define) name id
#include "%(msgs)s"
""" % { 'msgs': msgs })
p = subprocess.Popen(cpp + [tmp], stdout=subprocess.PIPE)
processed = p.communicate()[0]
os.remove(tmp)
return processed
def main():
debug = sys.argv[1] == '-d'
if debug:
sys.argv.pop(1)
output_file = sys.argv[1]
messages_file = sys.argv[2]
macros_file = sys.argv[3]
source_files = sys.argv[4:]
combined_file = 'selfhosted.js'
replaceErrorMsgs(source_files, messages_file, combined_file)
combined_sources = js2c.JS2C([combined_file, macros_file], [output_file], { 'TYPE': 'CORE', 'COMPRESSION': 'off', 'DEBUG':debug })
with open(combined_file, 'w') as output:
output.write(combined_sources)
env = {}
def define_env(option, opt, value, parser):
pair = value.split('=', 1)
if len(pair) == 1:
pair.append(1)
env[pair[0]] = pair[1]
p = OptionParser(usage="%prog [options] file")
p.add_option('-D', action='callback', callback=define_env, type="string",
metavar='var=[val]', help='Define a variable')
p.add_option('-m', type='string', metavar='jsmsg', default='../js.msg',
help='js.msg file')
p.add_option('-p', type='string', metavar='cpp', help='Path to C preprocessor')
p.add_option('-o', type='string', metavar='filename', default='selfhosted.out.h',
help='C array header file')
p.add_option('-s', type='string', metavar='jsfilename', default='selfhosted.js',
help='Combined postprocessed JS file')
(options, sources) = p.parse_args()
if not (options.p and sources):
p.print_help()
exit(1)
cpp = shlex.split(options.p)
embed(cpp, process_msgs(cpp, options.m),
sources, options.o, options.s, env)
if __name__ == "__main__":
main()
main()

View File

@ -1,351 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2012 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# This is a utility for converting JavaScript source code into C-style
# char arrays. It is used for embedded JavaScript code in the V8
# library.
import os, re, sys, string
import jsmin
import bz2
def ToCAsciiArray(lines):
result = []
for chr in lines:
value = ord(chr)
assert value < 128
result.append(str(value))
return ", ".join(result)
def ToCArray(lines):
result = []
for chr in lines:
result.append(str(ord(chr)))
return ", ".join(result)
def RemoveCommentsAndTrailingWhitespace(lines):
lines = re.sub(r'//.*\n', '\n', lines) # end-of-line comments
lines = re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', lines) # comments.
lines = re.sub(r'\s+\n+', '\n', lines) # trailing whitespace
return lines
def ReadFile(filename):
file = open(filename, "rt")
try:
lines = file.read()
finally:
file.close()
return lines
def ReadLines(filename):
result = []
for line in open(filename, "rt"):
if '#' in line:
line = line[:line.index('#')]
line = line.strip()
if len(line) > 0:
result.append(line)
return result
def LoadConfigFrom(name):
import ConfigParser
config = ConfigParser.ConfigParser()
config.read(name)
return config
def ParseValue(string):
string = string.strip()
if string.startswith('[') and string.endswith(']'):
return string.lstrip('[').rstrip(']').split()
else:
return string
EVAL_PATTERN = re.compile(r'\beval\s*\(')
WITH_PATTERN = re.compile(r'\bwith\s*\(')
def Validate(lines, file):
lines = RemoveCommentsAndTrailingWhitespace(lines)
# Because of simplified context setup, eval and with is not
# allowed in the natives files.
eval_match = EVAL_PATTERN.search(lines)
if eval_match:
raise ("Eval disallowed in natives: %s" % file)
with_match = WITH_PATTERN.search(lines)
if with_match:
raise ("With statements disallowed in natives: %s" % file)
def ExpandConstants(lines, constants):
for key, value in constants:
lines = key.sub(str(value), lines)
return lines
def ExpandMacros(lines, macros):
# We allow macros to depend on the previously declared macros, but
# we don't allow self-dependecies or recursion.
for name_pattern, macro in reversed(macros):
pattern_match = name_pattern.search(lines, 0)
while pattern_match is not None:
# Scan over the arguments
height = 1
start = pattern_match.start()
end = pattern_match.end()
assert lines[end - 1] == '('
last_match = end
arg_index = [0] # Wrap state into array, to work around Python "scoping"
mapping = { }
def add_arg(str):
# Remember to expand recursively in the arguments
replacement = ExpandMacros(str.strip(), macros)
mapping[macro.args[arg_index[0]]] = replacement
arg_index[0] += 1
while end < len(lines) and height > 0:
# We don't count commas at higher nesting levels.
if lines[end] == ',' and height == 1:
add_arg(lines[last_match:end])
last_match = end + 1
elif lines[end] in ['(', '{', '[']:
height = height + 1
elif lines[end] in [')', '}', ']']:
height = height - 1
end = end + 1
# Remember to add the last match.
add_arg(lines[last_match:end-1])
result = macro.expand(mapping)
# Replace the occurrence of the macro with the expansion
lines = lines[:start] + result + lines[end:]
pattern_match = name_pattern.search(lines, start + len(result))
return lines
class TextMacro:
def __init__(self, args, body):
self.args = args
self.body = body
def expand(self, mapping):
result = self.body
for key, value in mapping.items():
result = result.replace(key, value)
return result
class PythonMacro:
def __init__(self, args, fun):
self.args = args
self.fun = fun
def expand(self, mapping):
args = []
for arg in self.args:
args.append(mapping[arg])
return str(self.fun(*args))
CONST_PATTERN = re.compile(r'^const\s+([a-zA-Z0-9_]+)\s*=\s*([^;]*);$')
MACRO_PATTERN = re.compile(r'^macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
PYTHON_MACRO_PATTERN = re.compile(r'^python\s+macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
def ReadMacros(lines):
constants = []
macros = []
for line in lines:
hash = line.find('#')
if hash != -1: line = line[:hash]
line = line.strip()
if len(line) is 0: continue
const_match = CONST_PATTERN.match(line)
if const_match:
name = const_match.group(1)
value = const_match.group(2).strip()
constants.append((re.compile("\\b%s\\b" % name), value))
else:
macro_match = MACRO_PATTERN.match(line)
if macro_match:
name = macro_match.group(1)
args = [match.strip() for match in macro_match.group(2).split(',')]
body = macro_match.group(3).strip()
macros.append((re.compile("\\b%s\\(" % name), TextMacro(args, body)))
else:
python_match = PYTHON_MACRO_PATTERN.match(line)
if python_match:
name = python_match.group(1)
args = [match.strip() for match in python_match.group(2).split(',')]
body = python_match.group(3).strip()
fun = eval("lambda " + ",".join(args) + ': ' + body)
macros.append((re.compile("\\b%s\\(" % name), PythonMacro(args, fun)))
else:
raise ("Illegal line: " + line)
return (constants, macros)
HEADER_TEMPLATE = """\
/* 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/. */
namespace js {
namespace selfhosted {
static const char sources[] = { %(sources_data)s };
%(raw_sources_declaration)s\
uint32_t GetRawScriptsSize() {
return %(raw_total_length)i;
}
} // selfhosted
} // js
"""
RAW_SOURCES_COMPRESSION_DECLARATION = """\
static const char* raw_sources = NULL;
"""
RAW_SOURCES_DECLARATION = """\
static const char* raw_sources = reinterpret_cast<const char*>(sources);
"""
GET_INDEX_CASE = """\
if (strcmp(name, "%(id)s") == 0) return %(i)i;
"""
GET_RAW_SCRIPT_SOURCE_CASE = """\
if (index == %(i)i) return Vector<const char>(raw_sources + %(offset)i, %(raw_length)i);
"""
GET_SCRIPT_NAME_CASE = """\
if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i);
"""
def JS2C(source, target, env):
ids = []
debugger_ids = []
modules = []
# Locate the macros file name.
consts = []
macros = []
for s in source:
if 'macros.py' == (os.path.split(str(s))[1]):
(consts, macros) = ReadMacros(ReadLines(str(s)))
else:
modules.append(s)
minifier = jsmin.JavaScriptMinifier()
module_offset = 0
all_sources = []
for module in modules:
filename = str(module)
debugger = filename.endswith('-debugger.js')
lines = ReadFile(filename)
lines = ExpandConstants(lines, consts)
lines = ExpandMacros(lines, macros)
Validate(lines, filename)
# FIXME #824112
#if not env['DEBUG']:
# lines = minifier.JSMinify(lines)
id = (os.path.split(filename)[1])[:-3]
if debugger: id = id[:-9]
raw_length = len(lines)
if debugger:
debugger_ids.append((id, raw_length, module_offset))
else:
ids.append((id, raw_length, module_offset))
all_sources.append(lines)
module_offset += raw_length
total_length = raw_total_length = module_offset
if env['COMPRESSION'] == 'off':
raw_sources_declaration = RAW_SOURCES_DECLARATION
sources_data = ToCAsciiArray("".join(all_sources))
else:
raw_sources_declaration = RAW_SOURCES_COMPRESSION_DECLARATION
if env['COMPRESSION'] == 'bz2':
all_sources = bz2.compress("".join(all_sources))
total_length = len(all_sources)
sources_data = ToCArray(all_sources)
# Build debugger support functions
get_index_cases = [ ]
get_raw_script_source_cases = [ ]
get_script_name_cases = [ ]
i = 0
for (id, raw_length, module_offset) in debugger_ids + ids:
native_name = "native %s.js" % id
get_index_cases.append(GET_INDEX_CASE % { 'id': id, 'i': i })
get_raw_script_source_cases.append(GET_RAW_SCRIPT_SOURCE_CASE % {
'offset': module_offset,
'raw_length': raw_length,
'i': i
})
get_script_name_cases.append(GET_SCRIPT_NAME_CASE % {
'name': native_name,
'length': len(native_name),
'i': i
})
i = i + 1
# Emit result
output = open(str(target[0]), "w")
output.write(HEADER_TEMPLATE % {
'builtin_count': len(ids) + len(debugger_ids),
'debugger_count': len(debugger_ids),
'sources_data': sources_data,
'raw_sources_declaration': raw_sources_declaration,
'raw_total_length': raw_total_length,
'total_length': total_length,
'get_index_cases': "".join(get_index_cases),
'get_raw_script_source_cases': "".join(get_raw_script_source_cases),
'get_script_name_cases': "".join(get_script_name_cases),
'type': env['TYPE']
})
output.close()
return "".join(all_sources)
def main():
natives = sys.argv[1]
type = sys.argv[2]
compression = sys.argv[3]
source_files = sys.argv[4:]
JS2C(source_files, [natives], { 'TYPE': type, 'COMPRESSION': compression })
if __name__ == "__main__":
main()

View File

@ -1,282 +0,0 @@
#!/usr/bin/python2.4
# Copyright 2012 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""A JavaScript minifier.
It is far from being a complete JS parser, so there are many valid
JavaScript programs that will be ruined by it. Another strangeness is that
it accepts $ and % as parts of identifiers. It doesn't merge lines or strip
out blank lines in order to ease debugging. Variables at the top scope are
properties of the global object so we can't rename them. It is assumed that
you introduce variables with var as if JavaScript followed C++ scope rules
around curly braces, so the declaration must be above the first use.
Use as:
import jsmin
minifier = JavaScriptMinifier()
program1 = minifier.JSMinify(program1)
program2 = minifier.JSMinify(program2)
"""
import re
class JavaScriptMinifier(object):
"""An object that you can feed code snippets to to get them minified."""
def __init__(self):
# We prepopulate the list of identifiers that shouldn't be used. These
# short language keywords could otherwise be used by the script as variable
# names.
self.seen_identifiers = {"do": True, "in": True}
self.identifier_counter = 0
self.in_comment = False
self.map = {}
self.nesting = 0
def LookAtIdentifier(self, m):
"""Records identifiers or keywords that we see in use.
(So we can avoid renaming variables to these strings.)
Args:
m: The match object returned by re.search.
Returns:
Nothing.
"""
identifier = m.group(1)
self.seen_identifiers[identifier] = True
def Push(self):
"""Called when we encounter a '{'."""
self.nesting += 1
def Pop(self):
"""Called when we encounter a '}'."""
self.nesting -= 1
# We treat each top-level opening brace as a single scope that can span
# several sets of nested braces.
if self.nesting == 0:
self.map = {}
self.identifier_counter = 0
def Declaration(self, m):
"""Rewrites bits of the program selected by a regexp.
These can be curly braces, literal strings, function declarations and var
declarations. (These last two must be on one line including the opening
curly brace of the function for their variables to be renamed).
Args:
m: The match object returned by re.search.
Returns:
The string that should replace the match in the rewritten program.
"""
matched_text = m.group(0)
if matched_text == "{":
self.Push()
return matched_text
if matched_text == "}":
self.Pop()
return matched_text
if re.match("[\"'/]", matched_text):
return matched_text
m = re.match(r"var ", matched_text)
if m:
var_names = matched_text[m.end():]
var_names = re.split(r",", var_names)
return "var " + ",".join(map(self.FindNewName, var_names))
m = re.match(r"(function\b[^(]*)\((.*)\)\{$", matched_text)
if m:
up_to_args = m.group(1)
args = m.group(2)
args = re.split(r",", args)
self.Push()
return up_to_args + "(" + ",".join(map(self.FindNewName, args)) + "){"
if matched_text in self.map:
return self.map[matched_text]
return matched_text
def CharFromNumber(self, number):
"""A single-digit base-52 encoding using a-zA-Z."""
if number < 26:
return chr(number + 97)
number -= 26
return chr(number + 65)
def FindNewName(self, var_name):
"""Finds a new 1-character or 2-character name for a variable.
Enters it into the mapping table for this scope.
Args:
var_name: The name of the variable before renaming.
Returns:
The new name of the variable.
"""
new_identifier = ""
# Variable names that end in _ are member variables of the global object,
# so they can be visible from code in a different scope. We leave them
# alone.
if var_name in self.map:
return self.map[var_name]
if self.nesting == 0:
return var_name
while True:
identifier_first_char = self.identifier_counter % 52
identifier_second_char = self.identifier_counter // 52
new_identifier = self.CharFromNumber(identifier_first_char)
if identifier_second_char != 0:
new_identifier = (
self.CharFromNumber(identifier_second_char - 1) + new_identifier)
self.identifier_counter += 1
if not new_identifier in self.seen_identifiers:
break
self.map[var_name] = new_identifier
return new_identifier
def RemoveSpaces(self, m):
"""Returns literal strings unchanged, replaces other inputs with group 2.
Other inputs are replaced with the contents of capture 1. This is either
a single space or an empty string.
Args:
m: The match object returned by re.search.
Returns:
The string that should be inserted instead of the matched text.
"""
entire_match = m.group(0)
replacement = m.group(1)
if re.match(r"'.*'$", entire_match):
return entire_match
if re.match(r'".*"$', entire_match):
return entire_match
if re.match(r"/.+/$", entire_match):
return entire_match
return replacement
def JSMinify(self, text):
"""The main entry point. Takes a text and returns a compressed version.
The compressed version hopefully does the same thing. Line breaks are
preserved.
Args:
text: The text of the code snippet as a multiline string.
Returns:
The compressed text of the code snippet as a multiline string.
"""
new_lines = []
for line in re.split(r"\n", text):
line = line.replace("\t", " ")
if self.in_comment:
m = re.search(r"\*/", line)
if m:
line = line[m.end():]
self.in_comment = False
else:
new_lines.append("")
continue
if not self.in_comment:
line = re.sub(r"/\*.*?\*/", " ", line)
line = re.sub(r"//.*", "", line)
m = re.search(r"/\*", line)
if m:
line = line[:m.start()]
self.in_comment = True
# Strip leading and trailing spaces.
line = re.sub(r"^ +", "", line)
line = re.sub(r" +$", "", line)
# A regexp that matches a literal string surrounded by "double quotes".
# This regexp can handle embedded backslash-escaped characters including
# embedded backslash-escaped double quotes.
double_quoted_string = r'"(?:[^"\\]|\\.)*"'
# A regexp that matches a literal string surrounded by 'double quotes'.
single_quoted_string = r"'(?:[^'\\]|\\.)*'"
# A regexp that matches a regexp literal surrounded by /slashes/.
# Don't allow a regexp to have a ) before the first ( since that's a
# syntax error and it's probably just two unrelated slashes.
# Also don't allow it to come after anything that can only be the
# end of a primary expression.
slash_quoted_regexp = r"(?<![\w$'\")\]])/(?:(?=\()|(?:[^()/\\]|\\.)+)(?:\([^/\\]|\\.)*/"
# Replace multiple spaces with a single space.
line = re.sub("|".join([double_quoted_string,
single_quoted_string,
slash_quoted_regexp,
"( )+"]),
self.RemoveSpaces,
line)
# Strip single spaces unless they have an identifier character both before
# and after the space. % and $ are counted as identifier characters.
line = re.sub("|".join([double_quoted_string,
single_quoted_string,
slash_quoted_regexp,
r"(?<![a-zA-Z_0-9$%]) | (?![a-zA-Z_0-9$%])()"]),
self.RemoveSpaces,
line)
# Collect keywords and identifiers that are already in use.
if self.nesting == 0:
re.sub(r"([a-zA-Z0-9_$%]+)", self.LookAtIdentifier, line)
function_declaration_regexp = (
r"\bfunction" # Function definition keyword...
r"( [\w$%]+)?" # ...optional function name...
r"\([\w$%,]+\)\{") # ...argument declarations.
# Unfortunately the keyword-value syntax { key:value } makes the key look
# like a variable where in fact it is a literal string. We use the
# presence or absence of a question mark to try to distinguish between
# this case and the ternary operator: "condition ? iftrue : iffalse".
if re.search(r"\?", line):
block_trailing_colon = r""
else:
block_trailing_colon = r"(?![:\w$%])"
# Variable use. Cannot follow a period precede a colon.
variable_use_regexp = r"(?<![.\w$%])[\w$%]+" + block_trailing_colon
line = re.sub("|".join([double_quoted_string,
single_quoted_string,
slash_quoted_regexp,
r"\{", # Curly braces.
r"\}",
r"\bvar [\w$%,]+", # var declarations.
function_declaration_regexp,
variable_use_regexp]),
self.Declaration,
line)
new_lines.append(line)
return "\n".join(new_lines) + "\n"

View File

@ -1,259 +0,0 @@
# Copyright 2006-2009 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Dictionary that is passed as defines for js2c.py.
# Used for defines that must be defined for all native JS files.
const NONE = 0;
const READ_ONLY = 1;
const DONT_ENUM = 2;
const DONT_DELETE = 4;
# Constants used for getter and setter operations.
const GETTER = 0;
const SETTER = 1;
# These definitions must match the index of the properties in objects.h.
const kApiTagOffset = 0;
const kApiPropertyListOffset = 1;
const kApiSerialNumberOffset = 2;
const kApiConstructorOffset = 2;
const kApiPrototypeTemplateOffset = 5;
const kApiParentTemplateOffset = 6;
const kApiFlagOffset = 14;
const NO_HINT = 0;
const NUMBER_HINT = 1;
const STRING_HINT = 2;
const kFunctionTag = 0;
const kNewObjectTag = 1;
# For date.js.
const HoursPerDay = 24;
const MinutesPerHour = 60;
const SecondsPerMinute = 60;
const msPerSecond = 1000;
const msPerMinute = 60000;
const msPerHour = 3600000;
const msPerDay = 86400000;
const msPerMonth = 2592000000;
# For apinatives.js
const kUninitialized = -1;
const kReadOnlyPrototypeBit = 3; # For FunctionTemplateInfo, matches objects.h
# Note: kDayZeroInJulianDay = ToJulianDay(1970, 0, 1).
const kInvalidDate = 'Invalid Date';
const kDayZeroInJulianDay = 2440588;
const kMonthMask = 0x1e0;
const kDayMask = 0x01f;
const kYearShift = 9;
const kMonthShift = 5;
# Limits for parts of the date, so that we support all the dates that
# ECMA 262 - 15.9.1.1 requires us to, but at the same time be sure that
# the date (days since 1970) is in SMI range.
const kMinYear = -1000000;
const kMaxYear = 1000000;
const kMinMonth = -10000000;
const kMaxMonth = 10000000;
# Native cache ids.
const STRING_TO_REGEXP_CACHE_ID = 0;
# Type query macros.
#
# Note: We have special support for typeof(foo) === 'bar' in the compiler.
# It will *not* generate a runtime typeof call for the most important
# values of 'bar'.
macro IS_NULL(arg) = (arg === null);
macro IS_NULL_OR_UNDEFINED(arg) = (arg == null);
macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined');
macro IS_NUMBER(arg) = (typeof(arg) === 'number');
macro IS_STRING(arg) = (typeof(arg) === 'string');
macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
macro IS_OBJECT(arg) = (%_IsObject(arg));
macro IS_ARRAY(arg) = (%_IsArray(arg));
macro IS_FUNCTION(arg) = (%_IsFunction(arg));
macro IS_REGEXP(arg) = (%_IsRegExp(arg));
macro IS_SET(arg) = (%_ClassOf(arg) === 'Set');
macro IS_MAP(arg) = (%_ClassOf(arg) === 'Map');
macro IS_WEAKMAP(arg) = (%_ClassOf(arg) === 'WeakMap');
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String');
macro IS_BOOLEAN_WRAPPER(arg) = (%_ClassOf(arg) === 'Boolean');
macro IS_ERROR(arg) = (%_ClassOf(arg) === 'Error');
macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script');
macro IS_ARGUMENTS(arg) = (%_ClassOf(arg) === 'Arguments');
macro IS_GLOBAL(arg) = (%_ClassOf(arg) === 'global');
macro IS_UNDETECTABLE(arg) = (%_IsUndetectableObject(arg));
macro FLOOR(arg) = $floor(arg);
# Macro for ECMAScript 5 queries of the type:
# "Type(O) is object."
# This is the same as being either a function or an object in V8 terminology
# (including proxies).
# In addition, an undetectable object is also included by this.
macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg));
# Macro for ECMAScript 5 queries of the type:
# "IsCallable(O)"
# We assume here that this is the same as being either a function or a function
# proxy. That ignores host objects with [[Call]] methods, but in most situations
# we cannot handle those anyway.
macro IS_SPEC_FUNCTION(arg) = (%_ClassOf(arg) === 'Function');
# Indices in bound function info retrieved by %BoundFunctionGetBindings(...).
const kBoundFunctionIndex = 0;
const kBoundThisIndex = 1;
const kBoundArgumentsStartIndex = 2;
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0)));
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg)));
macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg)));
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
macro TO_UINT32(arg) = (arg >>> 0);
macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : NonStringToString(arg));
macro TO_NUMBER_INLINE(arg) = (IS_NUMBER(%IS_VAR(arg)) ? arg : NonNumberToNumber(arg));
macro TO_OBJECT_INLINE(arg) = (IS_SPEC_OBJECT(%IS_VAR(arg)) ? arg : ToObject(arg));
macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
# Macros implemented in Python.
python macro CHAR_CODE(str) = ord(str[1]);
# Constants used on an array to implement the properties of the RegExp object.
const REGEXP_NUMBER_OF_CAPTURES = 0;
const REGEXP_FIRST_CAPTURE = 3;
# We can't put macros in macros so we use constants here.
# REGEXP_NUMBER_OF_CAPTURES
macro NUMBER_OF_CAPTURES(array) = ((array)[0]);
# Limit according to ECMA 262 15.9.1.1
const MAX_TIME_MS = 8640000000000000;
# Limit which is MAX_TIME_MS + msPerMonth.
const MAX_TIME_BEFORE_UTC = 8640002592000000;
# Gets the value of a Date object. If arg is not a Date object
# a type error is thrown.
macro CHECK_DATE(arg) = if (%_ClassOf(arg) !== 'Date') ThrowDateTypeError();
macro LOCAL_DATE_VALUE(arg) = (%_DateField(arg, 0) + %_DateField(arg, 21));
macro UTC_DATE_VALUE(arg) = (%_DateField(arg, 0));
macro LOCAL_YEAR(arg) = (%_DateField(arg, 1));
macro LOCAL_MONTH(arg) = (%_DateField(arg, 2));
macro LOCAL_DAY(arg) = (%_DateField(arg, 3));
macro LOCAL_WEEKDAY(arg) = (%_DateField(arg, 4));
macro LOCAL_HOUR(arg) = (%_DateField(arg, 5));
macro LOCAL_MIN(arg) = (%_DateField(arg, 6));
macro LOCAL_SEC(arg) = (%_DateField(arg, 7));
macro LOCAL_MS(arg) = (%_DateField(arg, 8));
macro LOCAL_DAYS(arg) = (%_DateField(arg, 9));
macro LOCAL_TIME_IN_DAY(arg) = (%_DateField(arg, 10));
macro UTC_YEAR(arg) = (%_DateField(arg, 11));
macro UTC_MONTH(arg) = (%_DateField(arg, 12));
macro UTC_DAY(arg) = (%_DateField(arg, 13));
macro UTC_WEEKDAY(arg) = (%_DateField(arg, 14));
macro UTC_HOUR(arg) = (%_DateField(arg, 15));
macro UTC_MIN(arg) = (%_DateField(arg, 16));
macro UTC_SEC(arg) = (%_DateField(arg, 17));
macro UTC_MS(arg) = (%_DateField(arg, 18));
macro UTC_DAYS(arg) = (%_DateField(arg, 19));
macro UTC_TIME_IN_DAY(arg) = (%_DateField(arg, 20));
macro TIMEZONE_OFFSET(arg) = (%_DateField(arg, 21));
macro SET_UTC_DATE_VALUE(arg, value) = (%DateSetValue(arg, value, 1));
macro SET_LOCAL_DATE_VALUE(arg, value) = (%DateSetValue(arg, value, 0));
# Last input and last subject of regexp matches.
const LAST_SUBJECT_INDEX = 1;
macro LAST_SUBJECT(array) = ((array)[1]);
macro LAST_INPUT(array) = ((array)[2]);
# REGEXP_FIRST_CAPTURE
macro CAPTURE(index) = (3 + (index));
const CAPTURE0 = 3;
const CAPTURE1 = 4;
# For the regexp capture override array. This has the same
# format as the arguments to a function called from
# String.prototype.replace.
macro OVERRIDE_MATCH(override) = ((override)[0]);
macro OVERRIDE_POS(override) = ((override)[(override).length - 2]);
macro OVERRIDE_SUBJECT(override) = ((override)[(override).length - 1]);
# 1-based so index of 1 returns the first capture
macro OVERRIDE_CAPTURE(override, index) = ((override)[(index)]);
# The mode asserts options object for ParallelArray
macro TRY_PARALLEL(MODE) = ((!MODE || MODE.mode === "par"));
macro ASSERT_SEQUENTIAL_IS_OK(MODE) = do { if (MODE) AssertSequentialIsOK(MODE) } while(false);
# How many items at a time do we do recomp. for parallel execution.
# Note that filter currently assumes that this is no greater than 32
# in order to make use of a bitset.
const CHUNK_SHIFT = 5;
const CHUNK_SIZE = 32;
# Slice array: see ComputeAllSliceBounds() in ParallelArray.js
macro SLICE_INFO(START, END) = START, END, START, 0;
macro SLICE_START(ID) = ((ID << 2) + 0);
macro SLICE_END(ID) = ((ID << 2) + 1);
macro SLICE_POS(ID) = ((ID << 2) + 2);
# Safe version of ARRAY.push(ELEMENT)
macro ARRAY_PUSH(ARRAY, ELEMENT) = callFunction(std_Array_push, ARRAY, ELEMENT);
macro ARRAY_SLICE(ARRAY, ELEMENT) = callFunction(std_Array_slice, ARRAY, ELEMENT);
# PropertyDescriptor return value indices - must match
# PropertyDescriptorIndices in runtime.cc.
const IS_ACCESSOR_INDEX = 0;
const VALUE_INDEX = 1;
const GETTER_INDEX = 2;
const SETTER_INDEX = 3;
const WRITABLE_INDEX = 4;
const ENUMERABLE_INDEX = 5;
const CONFIGURABLE_INDEX = 6;
# For messages.js
# Matches Script::Type from objects.h
const TYPE_NATIVE = 0;
const TYPE_EXTENSION = 1;
const TYPE_NORMAL = 2;
# Matches Script::CompilationType from objects.h
const COMPILATION_TYPE_HOST = 0;
const COMPILATION_TYPE_EVAL = 1;
const COMPILATION_TYPE_JSON = 2;
# Matches Messages::kNoLineNumberInfo from v8.h
const kNoLineNumberInfo = 0;

View File

@ -27,6 +27,8 @@ using mozilla::DebugOnly;
void * const js::NullPtr::constNullValue = NULL;
JS_PUBLIC_DATA(void * const) JS::NullPtr::constNullValue = NULL;
/*
* There are two mostly separate mark paths. The first is a fast path used
* internally in the GC. The second is a slow path used for root marking and

View File

@ -4484,7 +4484,7 @@ CodeGenerator::link()
JSContext *cx = GetIonContext()->cx;
Linker linker(masm);
IonCode *code = linker.newCode(cx);
IonCode *code = linker.newCode(cx, JSC::ION_CODE);
if (!code)
return false;

View File

@ -97,7 +97,7 @@ IonCache::LinkStatus
IonCache::linkCode(JSContext *cx, MacroAssembler &masm, IonScript *ion, IonCode **code)
{
Linker linker(masm);
*code = linker.newCode(cx);
*code = linker.newCode(cx, JSC::ION_CODE);
if (!code)
return LINK_ERROR;

View File

@ -29,7 +29,10 @@ class Linker
return NULL;
}
IonCode *newCode(JSContext *cx, IonCompartment *comp) {
IonCode *newCode(JSContext *cx, IonCompartment *comp, JSC::CodeKind kind) {
JS_ASSERT(kind == JSC::ION_CODE ||
kind == JSC::BASELINE_CODE ||
kind == JSC::OTHER_CODE);
gc::AutoSuppressGC suppressGC(cx);
if (masm.oom())
return fail(cx);
@ -39,7 +42,7 @@ class Linker
if (bytesNeeded >= MAX_BUFFER_SIZE)
return fail(cx);
uint8_t *result = (uint8_t *)comp->execAlloc()->alloc(bytesNeeded, &pool, JSC::ION_CODE);
uint8_t *result = (uint8_t *)comp->execAlloc()->alloc(bytesNeeded, &pool, kind);
if (!result)
return fail(cx);
@ -67,8 +70,8 @@ class Linker
masm.finish();
}
IonCode *newCode(JSContext *cx) {
return newCode(cx, cx->compartment->ionCompartment());
IonCode *newCode(JSContext *cx, JSC::CodeKind kind) {
return newCode(cx, cx->compartment->ionCompartment(), kind);
}
};

View File

@ -196,7 +196,7 @@ IonRuntime::generateEnterJIT(JSContext *cx)
GenerateReturn(masm, JS_TRUE);
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
IonCode *
@ -242,7 +242,7 @@ IonRuntime::generateInvalidator(JSContext *cx)
masm.ma_add(sp, r1, sp);
masm.generateBailoutTail(r1);
Linker linker(masm);
IonCode *code = linker.newCode(cx);
IonCode *code = linker.newCode(cx, JSC::OTHER_CODE);
IonSpew(IonSpew_Invalidate, " invalidation thunk created at %p", (void *) code->raw());
return code;
}
@ -339,7 +339,7 @@ IonRuntime::generateArgumentsRectifier(JSContext *cx)
masm.ret();
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
static void
@ -447,7 +447,7 @@ IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
GenerateBailoutThunk(masm, frameClass);
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
IonCode *
@ -457,7 +457,7 @@ IonRuntime::generateBailoutHandler(JSContext *cx)
GenerateBailoutThunk(masm, NO_FRAME_SIZE_CLASS_ID);
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
IonCode *
@ -596,7 +596,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
masm.handleException();
Linker linker(masm);
IonCode *wrapper = linker.newCode(cx);
IonCode *wrapper = linker.newCode(cx, JSC::OTHER_CODE);
if (!wrapper)
return NULL;
@ -634,6 +634,6 @@ IonRuntime::generatePreBarrier(JSContext *cx, MIRType type)
masm.ret();
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}

View File

@ -176,7 +176,7 @@ IonRuntime::generateEnterJIT(JSContext *cx)
masm.ret();
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
IonCode *
@ -218,7 +218,7 @@ IonRuntime::generateInvalidator(JSContext *cx)
masm.generateBailoutTail(rdx);
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
IonCode *
@ -304,7 +304,7 @@ IonRuntime::generateArgumentsRectifier(JSContext *cx)
masm.ret();
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
static void
@ -359,7 +359,7 @@ IonRuntime::generateBailoutHandler(JSContext *cx)
GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
IonCode *
@ -504,7 +504,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
masm.handleException();
Linker linker(masm);
IonCode *wrapper = linker.newCode(cx);
IonCode *wrapper = linker.newCode(cx, JSC::OTHER_CODE);
if (!wrapper)
return NULL;
@ -542,6 +542,6 @@ IonRuntime::generatePreBarrier(JSContext *cx, MIRType type)
masm.ret();
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}

View File

@ -157,7 +157,7 @@ IonRuntime::generateEnterJIT(JSContext *cx)
masm.ret();
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
IonCode *
@ -205,7 +205,7 @@ IonRuntime::generateInvalidator(JSContext *cx)
masm.generateBailoutTail(edx);
Linker linker(masm);
IonCode *code = linker.newCode(cx);
IonCode *code = linker.newCode(cx, JSC::OTHER_CODE);
IonSpew(IonSpew_Invalidate, " invalidation thunk created at %p", (void *) code->raw());
return code;
}
@ -301,7 +301,7 @@ IonRuntime::generateArgumentsRectifier(JSContext *cx)
masm.ret();
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
static void
@ -369,7 +369,7 @@ IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
GenerateBailoutThunk(cx, masm, frameClass);
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
IonCode *
@ -380,7 +380,7 @@ IonRuntime::generateBailoutHandler(JSContext *cx)
GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}
IonCode *
@ -530,7 +530,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
masm.handleException();
Linker linker(masm);
IonCode *wrapper = linker.newCode(cx);
IonCode *wrapper = linker.newCode(cx, JSC::OTHER_CODE);
if (!wrapper)
return NULL;
@ -569,6 +569,6 @@ IonRuntime::generatePreBarrier(JSContext *cx, MIRType type)
masm.ret();
Linker linker(masm);
return linker.newCode(cx);
return linker.newCode(cx, JSC::OTHER_CODE);
}

View File

@ -5028,8 +5028,6 @@ using JS::MutableHandleString;
using JS::MutableHandleId;
using JS::MutableHandleValue;
using JS::NullPtr; /* To be removed by bug 781070. */
using JS::Zone;
} /* namespace js */

View File

@ -124,16 +124,9 @@ JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, JS::RuntimeSizes
rtSizes->temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
if (execAlloc_) {
execAlloc_->sizeOfCode(&rtSizes->jaegerCode, &rtSizes->ionCode, &rtSizes->asmJSCode,
&rtSizes->regexpCode, &rtSizes->unusedCode);
} else {
rtSizes->jaegerCode = 0;
rtSizes->ionCode = 0;
rtSizes->asmJSCode = 0;
rtSizes->regexpCode = 0;
rtSizes->unusedCode = 0;
}
rtSizes->code = JS::CodeSizes();
if (execAlloc_)
execAlloc_->sizeOfCode(&rtSizes->code);
rtSizes->regexpData = bumpAlloc_ ? bumpAlloc_->sizeOfNonHeapData() : 0;
@ -154,9 +147,10 @@ JSRuntime::sizeOfExplicitNonHeap()
size_t n = stackSpace.sizeOf();
if (execAlloc_) {
size_t jaegerCode, ionCode, asmJSCode, regexpCode, unusedCode;
execAlloc_->sizeOfCode(&jaegerCode, &ionCode, &asmJSCode, &regexpCode, &unusedCode);
n += jaegerCode + ionCode + asmJSCode + regexpCode + unusedCode;
JS::CodeSizes sizes;
execAlloc_->sizeOfCode(&sizes);
n += sizes.jaeger + sizes.ion + sizes.baseline + sizes.asmJS +
sizes.regexp + sizes.other + sizes.unused;
}
if (bumpAlloc_)

View File

@ -263,7 +263,7 @@ struct JSCompartment
/* Mark cross-compartment wrappers. */
void markCrossCompartmentWrappers(JSTracer *trc);
bool wrap(JSContext *cx, JS::MutableHandleValue vp, JS::HandleObject existing = JS::NullPtr());
bool wrap(JSContext *cx, JS::MutableHandleValue vp, JS::HandleObject existing = js::NullPtr());
bool wrap(JSContext *cx, JSString **strp);
bool wrap(JSContext *cx, js::HeapPtrString *strp);
bool wrap(JSContext *cx, JSObject **objp, JSObject *existing = NULL);

View File

@ -30,6 +30,7 @@
#include "selfhosted.out.h"
using namespace js;
using namespace js::selfhosted;
static void
selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
@ -517,8 +518,21 @@ JSRuntime::initSelfHosting(JSContext *cx)
if (script)
ok = Execute(cx, script, *shg.get(), &rv);
} else {
const char *src = selfhosted::raw_sources;
uint32_t srcLen = selfhosted::GetRawScriptsSize();
uint32_t srcLen = GetRawScriptsSize();
#ifdef USE_ZLIB
const unsigned char *compressed = compressedSources;
uint32_t compressedLen = GetCompressedSize();
ScopedJSFreePtr<char> src(reinterpret_cast<char *>(cx->malloc_(srcLen)));
if (!src || !DecompressString(compressed, compressedLen,
reinterpret_cast<unsigned char *>(src.get()), srcLen))
{
return false;
}
#else
const char *src = rawSources;
#endif
ok = Evaluate(cx, shg, options, src, srcLen, &rv);
}
JS_SetErrorReporter(cx, oldReporter);

View File

@ -1950,28 +1950,35 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
"Memory held transiently in JSRuntime and used during "
"compilation. It mostly holds parse nodes.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/jaeger-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.jaegerCode,
"Memory used by the JaegerMonkey JIT to hold the runtime's "
"generated code.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/jaeger"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.jaeger,
"Memory used by the JaegerMonkey JIT to hold generated code.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/ion-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.ionCode,
"Memory used by the IonMonkey JIT to hold the runtime's "
"generated code.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/ion"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.ion,
"Memory used by the IonMonkey JIT to hold generated code.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/asm.js-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.asmJSCode,
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/baseline"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.baseline,
"Memory used by the Baseline JIT to hold generated code.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/asm.js"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.asmJS,
"Memory used by AOT-compiled asm.js code.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/regexp-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.regexpCode,
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/regexp"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.regexp,
"Memory used by the regexp JIT to hold generated code.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/unused-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.unusedCode,
"Memory allocated by one of the JITs to hold the "
"runtime's code, but which is currently unused.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/other"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.other,
"Memory used by the JITs to hold generated code for "
"wrappers and trampolines.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/unused"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.unused,
"Memory allocated by one of the JITs to hold code, "
"but which is currently unused.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/regexp-data"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.regexpData,

View File

@ -2136,7 +2136,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
// Note that items without their own layers can't be skipped this
// way, since their ThebesLayer may decide it wants to draw them
// into its buffer even if they're currently covered.
if (itemVisibleRect.IsEmpty() && layerState != LAYER_ACTIVE_EMPTY) {
if (itemVisibleRect.IsEmpty() &&
!item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
continue;
}
@ -2192,7 +2193,9 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
data->mDrawAboveRegion.SimplifyOutward(4);
}
itemVisibleRect.MoveBy(mParameters.mOffset);
RestrictVisibleRegionForLayer(ownLayer, itemVisibleRect);
if (!nsDisplayTransform::IsLayerPrerendered(ownLayer)) {
RestrictVisibleRegionForLayer(ownLayer, itemVisibleRect);
}
// rounded rectangle clipping using mask layers
// (must be done after visible rect is set on layer)

View File

@ -570,12 +570,24 @@ void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
nsRect dirty = aDirtyRect - aFrame->GetOffsetTo(aDirtyFrame);
nsRect overflowRect = aFrame->GetVisualOverflowRect();
if (aFrame->IsTransformed() &&
nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
eCSSProperty_transform)) {
/**
* Add a fuzz factor to the overflow rectangle so that elements only just
* out of view are pulled into the display list, so they can be
* prerendered if necessary.
*/
overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
}
if (mHasDisplayPort && IsFixedFrame(aFrame)) {
dirty = overflowRect;
}
if (!dirty.IntersectRect(dirty, overflowRect))
return;
aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDirtyRectProperty(),
new nsRect(dirty));
@ -3891,7 +3903,14 @@ nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBui
nsIFrame* aFrame,
bool aLogAnimations)
{
if (!aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
// Elements whose transform has been modified recently, or which
// have a compositor-animated transform, can be prerendered. An element
// might have only just had its transform animated in which case
// nsChangeHint_UpdateTransformLayer will not be present yet.
if (!aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
(!aFrame->GetContent() ||
!nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
eCSSProperty_transform))) {
if (aLogAnimations) {
nsCString message;
message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
@ -3978,6 +3997,12 @@ nsDisplayTransform::GetTransform(float aAppUnitsPerPixel)
return mTransform;
}
bool
nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
{
return ShouldPrerenderTransformedContent(aBuilder, mFrame, false);
}
already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
LayerManager *aManager,
const ContainerParameters& aContainerParameters)

View File

@ -966,6 +966,12 @@ public:
LayerManager* aManager,
const ContainerParameters& aParameters)
{ return mozilla::LAYER_NONE; }
/**
* Return true to indicate the layer should be constructed even if it's
* completely invisible.
*/
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
{ return false; }
/**
* Actually paint this item to some rendering context.
* Content outside mVisibleRect need not be painted.
@ -2533,7 +2539,8 @@ public:
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aParameters) MOZ_OVERRIDE;
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
{ return true; }
virtual bool TryMerge(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem) MOZ_OVERRIDE;
@ -2789,6 +2796,7 @@ public:
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) MOZ_OVERRIDE;
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
virtual bool ComputeVisibility(nsDisplayListBuilder *aBuilder,
nsRegion *aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
@ -2940,6 +2948,11 @@ public:
bool aLogAnimations = false);
bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
static bool IsLayerPrerendered(Layer* aLayer)
{
return aLayer->HasUserData(nsIFrame::LayerIsPrerenderedDataKey());
}
private:
static gfx3DMatrix GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties,
const nsPoint& aOrigin,

View File

@ -130,10 +130,6 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
}
for (nsDisplayItem* i = aList.GetBottom(); i != nullptr; i = i->GetAbove()) {
#ifdef DEBUG
if (aList.DidComputeVisibility() && i->GetVisibleRect().IsEmpty())
continue;
#endif
if (aDumpHtml) {
fprintf(aOutput, "<li>");
} else {

View File

@ -2054,6 +2054,18 @@ IsRootScrollFrameActive(nsIPresShell* aPresShell)
return sf && sf->IsScrollingActive();
}
static nsDisplayItem*
WrapInWrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList)
{
nsDisplayItem* item = aList->GetBottom();
if (!item || item->GetAbove() || item->GetUnderlyingFrame() != aFrame) {
return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList);
}
aList->RemoveBottom();
return item;
}
void
nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
nsIFrame* aChild,
@ -2288,7 +2300,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
if (buildFixedPositionItem) {
item = new (aBuilder) nsDisplayFixedPosition(aBuilder, child, child, &list);
} else {
item = new (aBuilder) nsDisplayWrapList(aBuilder, child, &list);
item = WrapInWrapList(aBuilder, child, &list);
}
if (isSVG) {
aLists.Content()->AppendNewToTop(item);
@ -2311,8 +2323,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
}
} else if (!isSVG && disp->IsFloating(child)) {
if (!list.IsEmpty()) {
aLists.Floats()->AppendNewToTop(new (aBuilder)
nsDisplayWrapList(aBuilder, child, &list));
aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list));
}
} else {
aLists.Content()->AppendToTop(&list);

View File

@ -53,7 +53,7 @@ public:
* @result The new view. Never null.
*/
nsView* CreateView(const nsRect& aBounds,
const nsView* aParent,
nsView* aParent,
nsViewVisibility aVisibilityFlag = nsViewVisibility_kShow);
/**

View File

@ -126,11 +126,11 @@ nsViewManager::Init(nsDeviceContext* aContext)
nsView*
nsViewManager::CreateView(const nsRect& aBounds,
const nsView* aParent,
nsView* aParent,
nsViewVisibility aVisibilityFlag)
{
nsView *v = new nsView(this, aVisibilityFlag);
v->SetParent(const_cast<nsView*>(aParent));
v->SetParent(aParent);
v->SetPosition(aBounds.x, aBounds.y);
nsRect dim(0, 0, aBounds.width, aBounds.height);
v->SetDimensions(dim, false);