mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Merge m-c to b-i
This commit is contained in:
commit
6e34c70597
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 870366 - Blacklisting PREF_JS_EXPORTS in Makefile.ins (because of 852814)
|
||||
Bug 1109248 - This needed a CLOBBER on Windows and OSX.
|
||||
|
@ -83,10 +83,14 @@ exports.RecordingUtils.getSamplesFromAllocations = function(allocations) {
|
||||
samples.push(sample);
|
||||
|
||||
while (frame) {
|
||||
let source = frame.source + ":" + frame.line + ":" + frame.column;
|
||||
let funcName = frame.functionDisplayName || "";
|
||||
|
||||
sample.frames.push({
|
||||
location: frame.source + ":" + frame.line + ":" + frame.column,
|
||||
location: funcName ? funcName + " (" + source + ")" : source,
|
||||
allocations: count
|
||||
});
|
||||
|
||||
site = frame.parent;
|
||||
frame = frames[site];
|
||||
count = counts[site];
|
||||
|
@ -25,18 +25,21 @@ let TEST_DATA = {
|
||||
source: "A",
|
||||
line: 1,
|
||||
column: 2,
|
||||
functionDisplayName: "x",
|
||||
parent: 0
|
||||
},
|
||||
{
|
||||
source: "B",
|
||||
line: 3,
|
||||
column: 4,
|
||||
functionDisplayName: "y",
|
||||
parent: 1
|
||||
},
|
||||
{
|
||||
source: "C",
|
||||
line: 5,
|
||||
column: 6,
|
||||
functionDisplayName: null,
|
||||
parent: 2
|
||||
}
|
||||
],
|
||||
@ -52,25 +55,25 @@ let EXPECTED_OUTPUT = [{
|
||||
}, {
|
||||
time: 150,
|
||||
frames: [{
|
||||
location: "A:1:2",
|
||||
location: "x (A:1:2)",
|
||||
allocations: 22
|
||||
}]
|
||||
}, {
|
||||
time: 200,
|
||||
frames: [{
|
||||
location: "A:1:2",
|
||||
location: "x (A:1:2)",
|
||||
allocations: 22
|
||||
}, {
|
||||
location: "B:3:4",
|
||||
location: "y (B:3:4)",
|
||||
allocations: 33
|
||||
}]
|
||||
}, {
|
||||
time: 250,
|
||||
frames: [{
|
||||
location: "A:1:2",
|
||||
location: "x (A:1:2)",
|
||||
allocations: 22
|
||||
}, {
|
||||
location: "B:3:4",
|
||||
location: "y (B:3:4)",
|
||||
allocations: 33
|
||||
}, {
|
||||
location: "C:5:6",
|
||||
|
@ -90,7 +90,6 @@ _MOZBUILD_EXTERNAL_VARIABLES := \
|
||||
NO_DIST_INSTALL \
|
||||
OS_LIBS \
|
||||
PARALLEL_DIRS \
|
||||
PREF_JS_EXPORTS \
|
||||
PROGRAM \
|
||||
PYTHON_UNIT_TESTS \
|
||||
RESOURCE_FILES \
|
||||
|
@ -71,7 +71,7 @@ GCONF_VERSION=1.2.1
|
||||
GIO_VERSION=2.20
|
||||
STARTUP_NOTIFICATION_VERSION=0.8
|
||||
DBUS_VERSION=0.60
|
||||
SQLITE_VERSION=3.8.8.1
|
||||
SQLITE_VERSION=3.8.8.2
|
||||
|
||||
MSMANIFEST_TOOL=
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
This is SQLite 3.8.8.1
|
||||
This is the SQLite amalgamation.
|
||||
Check sqlite3.h for the version number and source id.
|
||||
|
||||
See http://www.sqlite.org/ for more info.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/******************************************************************************
|
||||
** This file is an amalgamation of many separate C source files from SQLite
|
||||
** version 3.8.8.1. By combining all the individual C code files into this
|
||||
** version 3.8.8.2. By combining all the individual C code files into this
|
||||
** single large file, the entire code can be compiled as a single translation
|
||||
** unit. This allows many compilers to do optimizations that would not be
|
||||
** possible if the files were compiled separately. Performance improvements
|
||||
@ -278,9 +278,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.8.8.1"
|
||||
#define SQLITE_VERSION "3.8.8.2"
|
||||
#define SQLITE_VERSION_NUMBER 3008008
|
||||
#define SQLITE_SOURCE_ID "2015-01-20 16:51:25 f73337e3e289915a76ca96e7a05a1a8d4e890d55"
|
||||
#define SQLITE_SOURCE_ID "2015-01-30 14:30:45 7757fc721220e136620a89c9d28247f28bbbc098"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@ -50197,7 +50197,7 @@ static int walCheckpoint(
|
||||
int sync_flags, /* Flags for OsSync() (or 0) */
|
||||
u8 *zBuf /* Temporary buffer to use */
|
||||
){
|
||||
int rc; /* Return code */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int szPage; /* Database page-size */
|
||||
WalIterator *pIter = 0; /* Wal iterator context */
|
||||
u32 iDbpage = 0; /* Next database page to write */
|
||||
@ -50211,104 +50211,107 @@ static int walCheckpoint(
|
||||
testcase( szPage<=32768 );
|
||||
testcase( szPage>=65536 );
|
||||
pInfo = walCkptInfo(pWal);
|
||||
if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
|
||||
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
|
||||
|
||||
/* Allocate the iterator */
|
||||
rc = walIteratorInit(pWal, &pIter);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
assert( pIter );
|
||||
|
||||
/* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
|
||||
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
|
||||
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
|
||||
|
||||
/* Compute in mxSafeFrame the index of the last frame of the WAL that is
|
||||
** safe to write into the database. Frames beyond mxSafeFrame might
|
||||
** overwrite database pages that are in use by active readers and thus
|
||||
** cannot be backfilled from the WAL.
|
||||
*/
|
||||
mxSafeFrame = pWal->hdr.mxFrame;
|
||||
mxPage = pWal->hdr.nPage;
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
u32 y = pInfo->aReadMark[i];
|
||||
if( mxSafeFrame>y ){
|
||||
assert( y<=pWal->hdr.mxFrame );
|
||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
}else if( rc==SQLITE_BUSY ){
|
||||
mxSafeFrame = y;
|
||||
xBusy = 0;
|
||||
}else{
|
||||
goto walcheckpoint_out;
|
||||
}
|
||||
/* Allocate the iterator */
|
||||
rc = walIteratorInit(pWal, &pIter);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
assert( pIter );
|
||||
|
||||
if( pInfo->nBackfill<mxSafeFrame
|
||||
&& (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
|
||||
){
|
||||
i64 nSize; /* Current size of database file */
|
||||
u32 nBackfill = pInfo->nBackfill;
|
||||
/* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
|
||||
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
|
||||
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
|
||||
|
||||
/* Sync the WAL to disk */
|
||||
if( sync_flags ){
|
||||
rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
|
||||
}
|
||||
|
||||
/* If the database may grow as a result of this checkpoint, hint
|
||||
** about the eventual size of the db file to the VFS layer.
|
||||
/* Compute in mxSafeFrame the index of the last frame of the WAL that is
|
||||
** safe to write into the database. Frames beyond mxSafeFrame might
|
||||
** overwrite database pages that are in use by active readers and thus
|
||||
** cannot be backfilled from the WAL.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
i64 nReq = ((i64)mxPage * szPage);
|
||||
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
|
||||
if( rc==SQLITE_OK && nSize<nReq ){
|
||||
sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Iterate through the contents of the WAL, copying data to the db file. */
|
||||
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
|
||||
i64 iOffset;
|
||||
assert( walFramePgno(pWal, iFrame)==iDbpage );
|
||||
if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
|
||||
iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
|
||||
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
|
||||
rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
iOffset = (iDbpage-1)*(i64)szPage;
|
||||
testcase( IS_BIG_INT(iOffset) );
|
||||
rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
|
||||
/* If work was actually accomplished... */
|
||||
if( rc==SQLITE_OK ){
|
||||
if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
|
||||
i64 szDb = pWal->hdr.nPage*(i64)szPage;
|
||||
testcase( IS_BIG_INT(szDb) );
|
||||
rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
|
||||
if( rc==SQLITE_OK && sync_flags ){
|
||||
rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
|
||||
mxSafeFrame = pWal->hdr.mxFrame;
|
||||
mxPage = pWal->hdr.nPage;
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
u32 y = pInfo->aReadMark[i];
|
||||
if( mxSafeFrame>y ){
|
||||
assert( y<=pWal->hdr.mxFrame );
|
||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
}else if( rc==SQLITE_BUSY ){
|
||||
mxSafeFrame = y;
|
||||
xBusy = 0;
|
||||
}else{
|
||||
goto walcheckpoint_out;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pInfo->nBackfill = mxSafeFrame;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the reader lock held while backfilling */
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
|
||||
}
|
||||
if( pInfo->nBackfill<mxSafeFrame
|
||||
&& (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
|
||||
){
|
||||
i64 nSize; /* Current size of database file */
|
||||
u32 nBackfill = pInfo->nBackfill;
|
||||
|
||||
if( rc==SQLITE_BUSY ){
|
||||
/* Reset the return code so as not to report a checkpoint failure
|
||||
** just because there are active readers. */
|
||||
rc = SQLITE_OK;
|
||||
/* Sync the WAL to disk */
|
||||
if( sync_flags ){
|
||||
rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
|
||||
}
|
||||
|
||||
/* If the database may grow as a result of this checkpoint, hint
|
||||
** about the eventual size of the db file to the VFS layer.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
i64 nReq = ((i64)mxPage * szPage);
|
||||
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
|
||||
if( rc==SQLITE_OK && nSize<nReq ){
|
||||
sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Iterate through the contents of the WAL, copying data to the db file */
|
||||
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
|
||||
i64 iOffset;
|
||||
assert( walFramePgno(pWal, iFrame)==iDbpage );
|
||||
if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
|
||||
continue;
|
||||
}
|
||||
iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
|
||||
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
|
||||
rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
iOffset = (iDbpage-1)*(i64)szPage;
|
||||
testcase( IS_BIG_INT(iOffset) );
|
||||
rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
|
||||
/* If work was actually accomplished... */
|
||||
if( rc==SQLITE_OK ){
|
||||
if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
|
||||
i64 szDb = pWal->hdr.nPage*(i64)szPage;
|
||||
testcase( IS_BIG_INT(szDb) );
|
||||
rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
|
||||
if( rc==SQLITE_OK && sync_flags ){
|
||||
rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pInfo->nBackfill = mxSafeFrame;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the reader lock held while backfilling */
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_BUSY ){
|
||||
/* Reset the return code so as not to report a checkpoint failure
|
||||
** just because there are active readers. */
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
|
||||
@ -50323,7 +50326,7 @@ static int walCheckpoint(
|
||||
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
|
||||
u32 salt1;
|
||||
sqlite3_randomness(4, &salt1);
|
||||
assert( mxSafeFrame==pWal->hdr.mxFrame );
|
||||
assert( pInfo->nBackfill==pWal->hdr.mxFrame );
|
||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
|
||||
@ -128369,6 +128372,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb);
|
||||
}else{
|
||||
db->busyHandler.nBusy = 0;
|
||||
rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
|
||||
sqlite3Error(db, rc);
|
||||
}
|
||||
|
@ -107,9 +107,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.8.8.1"
|
||||
#define SQLITE_VERSION "3.8.8.2"
|
||||
#define SQLITE_VERSION_NUMBER 3008008
|
||||
#define SQLITE_SOURCE_ID "2015-01-20 16:51:25 f73337e3e289915a76ca96e7a05a1a8d4e890d55"
|
||||
#define SQLITE_SOURCE_ID "2015-01-30 14:30:45 7757fc721220e136620a89c9d28247f28bbbc098"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
|
@ -2075,7 +2075,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||
if (aWin->GetDoc()) {
|
||||
aWin->GetDoc()->WarnOnceAbout(nsIDocument::eWindow_Controllers);
|
||||
}
|
||||
JS::Rooted<JSObject*> shim(cx, JS_NewObject(cx, &ControllersShimClass, JS::NullPtr(), obj));
|
||||
JS::Rooted<JSObject*> shim(cx, JS_NewObject(cx, &ControllersShimClass, obj));
|
||||
if (NS_WARN_IF(!shim)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -6154,7 +6154,7 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
|
||||
}
|
||||
|
||||
if (!aOptions.mPrototype) {
|
||||
protoObject = JS_NewObject(aCx, nullptr, htmlProto, JS::NullPtr());
|
||||
protoObject = JS_NewObjectWithGivenProto(aCx, nullptr, htmlProto, JS::NullPtr());
|
||||
if (!protoObject) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
|
@ -481,8 +481,8 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
|
||||
JS::Rooted<JSObject*> constructor(cx);
|
||||
if (constructorClass) {
|
||||
MOZ_ASSERT(constructorProto);
|
||||
constructor = JS_NewObject(cx, Jsvalify(constructorClass), constructorProto,
|
||||
global);
|
||||
constructor = JS_NewObjectWithGivenProto(cx, Jsvalify(constructorClass),
|
||||
constructorProto, global);
|
||||
} else {
|
||||
MOZ_ASSERT(constructorNative);
|
||||
MOZ_ASSERT(constructorProto == JS_GetFunctionPrototype(cx, global));
|
||||
|
@ -2798,7 +2798,7 @@ public:
|
||||
JS::Handle<JSObject*> aProto, JS::Handle<JSObject*> aParent,
|
||||
T* aNative, JS::MutableHandle<JSObject*> aReflector)
|
||||
{
|
||||
aReflector.set(JS_NewObject(aCx, aClass, aProto, aParent));
|
||||
aReflector.set(JS_NewObjectWithGivenProto(aCx, aClass, aProto, aParent));
|
||||
if (aReflector) {
|
||||
js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
|
||||
mNative = aNative;
|
||||
|
@ -172,8 +172,7 @@ GetJSValFromKeyPathString(JSContext* aCx,
|
||||
}
|
||||
else {
|
||||
JS::Rooted<JSObject*> dummy(aCx,
|
||||
JS_NewObject(aCx, IDBObjectStore::DummyPropClass(), JS::NullPtr(),
|
||||
JS::NullPtr()));
|
||||
JS_NewObject(aCx, IDBObjectStore::DummyPropClass()));
|
||||
if (!dummy) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
|
@ -124,10 +124,10 @@ class TabChild::DelayedFireSingleTapEvent MOZ_FINAL : public nsITimerCallback
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
DelayedFireSingleTapEvent(TabChild* aTabChild,
|
||||
DelayedFireSingleTapEvent(nsIWidget* aWidget,
|
||||
LayoutDevicePoint& aPoint,
|
||||
nsITimer* aTimer)
|
||||
: mTabChild(do_GetWeakReference(static_cast<nsITabChild*>(aTabChild)))
|
||||
: mWidget(do_GetWeakReference(aWidget))
|
||||
, mPoint(aPoint)
|
||||
// Hold the reference count until we are called back.
|
||||
, mTimer(aTimer)
|
||||
@ -136,9 +136,9 @@ public:
|
||||
|
||||
NS_IMETHODIMP Notify(nsITimer*) MOZ_OVERRIDE
|
||||
{
|
||||
nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(mTabChild);
|
||||
if (tabChild) {
|
||||
static_cast<TabChild*>(tabChild.get())->FireSingleTapEvent(mPoint);
|
||||
nsCOMPtr<nsIWidget> widget = do_QueryReferent(mWidget);
|
||||
if (widget) {
|
||||
APZCCallbackHelper::FireSingleTapEvent(mPoint, widget);
|
||||
}
|
||||
mTimer = nullptr;
|
||||
return NS_OK;
|
||||
@ -153,7 +153,7 @@ private:
|
||||
{
|
||||
}
|
||||
|
||||
nsWeakPtr mTabChild;
|
||||
nsWeakPtr mWidget;
|
||||
LayoutDevicePoint mPoint;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
};
|
||||
@ -602,46 +602,6 @@ TabChildBase::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
|
||||
return newMetrics;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
TabChildBase::DispatchSynthesizedMouseEvent(uint32_t aMsg, uint64_t aTime,
|
||||
const LayoutDevicePoint& aRefPoint,
|
||||
nsIWidget* aWidget)
|
||||
{
|
||||
MOZ_ASSERT(aMsg == NS_MOUSE_MOVE || aMsg == NS_MOUSE_BUTTON_DOWN ||
|
||||
aMsg == NS_MOUSE_BUTTON_UP || aMsg == NS_MOUSE_MOZLONGTAP);
|
||||
|
||||
WidgetMouseEvent event(true, aMsg, nullptr,
|
||||
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
|
||||
event.refPoint = LayoutDeviceIntPoint(aRefPoint.x, aRefPoint.y);
|
||||
event.time = aTime;
|
||||
event.button = WidgetMouseEvent::eLeftButton;
|
||||
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
event.ignoreRootScrollFrame = true;
|
||||
if (aMsg != NS_MOUSE_MOVE) {
|
||||
event.clickCount = 1;
|
||||
}
|
||||
event.widget = aWidget;
|
||||
|
||||
return DispatchWidgetEvent(event);
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
TabChildBase::DispatchWidgetEvent(WidgetGUIEvent& event)
|
||||
{
|
||||
if (!event.widget)
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
|
||||
if (TabParent* capturer = TabParent::GetEventCapturer()) {
|
||||
if (capturer->TryCapture(event)) {
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
}
|
||||
nsEventStatus status;
|
||||
NS_ENSURE_SUCCESS(event.widget->DispatchEvent(&event, status),
|
||||
nsEventStatus_eConsumeNoDefault);
|
||||
return status;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChildBase::IsAsyncPanZoomEnabled()
|
||||
{
|
||||
@ -2155,14 +2115,14 @@ TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid&
|
||||
// If the active element isn't visually affected by the :active style, we
|
||||
// have no need to wait the extra sActiveDurationMs to make the activation
|
||||
// visually obvious to the user.
|
||||
FireSingleTapEvent(currentPoint);
|
||||
APZCCallbackHelper::FireSingleTapEvent(currentPoint, mWidget);
|
||||
return true;
|
||||
}
|
||||
|
||||
TABC_LOG("Active element uses style, scheduling timer for click event\n");
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
nsRefPtr<DelayedFireSingleTapEvent> callback =
|
||||
new DelayedFireSingleTapEvent(this, currentPoint, timer);
|
||||
new DelayedFireSingleTapEvent(mWidget, currentPoint, timer);
|
||||
nsresult rv = timer->InitWithCallback(callback,
|
||||
sActiveDurationMs,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
@ -2174,20 +2134,6 @@ TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid&
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TabChild::FireSingleTapEvent(LayoutDevicePoint aPoint)
|
||||
{
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
TABC_LOG("Dispatching single-tap component events to %s\n",
|
||||
Stringify(aPoint).c_str());
|
||||
int time = 0;
|
||||
DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, aPoint, mWidget);
|
||||
DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, aPoint, mWidget);
|
||||
DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, aPoint, mWidget);
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
|
||||
{
|
||||
@ -2215,7 +2161,7 @@ TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& a
|
||||
* mWidget->GetDefaultScale();
|
||||
int time = 0;
|
||||
nsEventStatus status =
|
||||
DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, mWidget);
|
||||
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, mWidget);
|
||||
eventHandled = (status == nsEventStatus_eConsumeNoDefault);
|
||||
TABC_LOG("MOZLONGTAP event handled: %d\n", eventHandled);
|
||||
}
|
||||
@ -2342,7 +2288,7 @@ TabChild::RecvRealMouseEvent(const WidgetMouseEvent& event)
|
||||
{
|
||||
WidgetMouseEvent localEvent(event);
|
||||
localEvent.widget = mWidget;
|
||||
DispatchWidgetEvent(localEvent);
|
||||
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2367,7 +2313,7 @@ TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent,
|
||||
|
||||
WidgetWheelEvent event(aEvent);
|
||||
event.widget = mWidget;
|
||||
DispatchWidgetEvent(event);
|
||||
APZCCallbackHelper::DispatchWidgetEvent(event);
|
||||
|
||||
if (IsAsyncPanZoomEnabled()) {
|
||||
SendContentReceivedInputBlock(aGuid, aInputBlockId, event.mFlags.mDefaultPrevented);
|
||||
@ -2461,9 +2407,9 @@ TabChild::UpdateTapState(const WidgetTouchEvent& aEvent, nsEventStatus aStatus)
|
||||
|
||||
case NS_TOUCH_END:
|
||||
if (!nsIPresShell::gPreventMouseEvents) {
|
||||
DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, currentPoint, mWidget);
|
||||
DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, currentPoint, mWidget);
|
||||
DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, currentPoint, mWidget);
|
||||
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, currentPoint, mWidget);
|
||||
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, currentPoint, mWidget);
|
||||
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, currentPoint, mWidget);
|
||||
}
|
||||
// fall through
|
||||
case NS_TOUCH_CANCEL:
|
||||
@ -2702,7 +2648,7 @@ TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
WidgetTouchEvent localEvent(aEvent);
|
||||
localEvent.widget = mWidget;
|
||||
// Dispatch event to content (potentially a long-running operation)
|
||||
nsEventStatus status = DispatchWidgetEvent(localEvent);
|
||||
nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
|
||||
|
||||
if (!IsAsyncPanZoomEnabled()) {
|
||||
UpdateTapState(localEvent, status);
|
||||
@ -2807,7 +2753,7 @@ TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
|
||||
|
||||
WidgetKeyboardEvent localEvent(event);
|
||||
localEvent.widget = mWidget;
|
||||
nsEventStatus status = DispatchWidgetEvent(localEvent);
|
||||
nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
|
||||
|
||||
if (event.message == NS_KEY_DOWN) {
|
||||
mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
|
||||
@ -2844,7 +2790,7 @@ TabChild::RecvCompositionEvent(const WidgetCompositionEvent& event)
|
||||
{
|
||||
WidgetCompositionEvent localEvent(event);
|
||||
localEvent.widget = mWidget;
|
||||
DispatchWidgetEvent(localEvent);
|
||||
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2853,7 +2799,7 @@ TabChild::RecvSelectionEvent(const WidgetSelectionEvent& event)
|
||||
{
|
||||
WidgetSelectionEvent localEvent(event);
|
||||
localEvent.widget = mWidget;
|
||||
DispatchWidgetEvent(localEvent);
|
||||
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -196,10 +196,6 @@ public:
|
||||
const bool& aIsRoot,
|
||||
const mozilla::layers::ZoomConstraints& aConstraints) = 0;
|
||||
|
||||
nsEventStatus DispatchSynthesizedMouseEvent(uint32_t aMsg, uint64_t aTime,
|
||||
const LayoutDevicePoint& aRefPoint,
|
||||
nsIWidget* aWidget);
|
||||
|
||||
protected:
|
||||
virtual ~TabChildBase();
|
||||
CSSSize GetPageSize(nsCOMPtr<nsIDocument> aDocument, const CSSSize& aViewport);
|
||||
@ -221,8 +217,6 @@ protected:
|
||||
void DispatchMessageManagerMessage(const nsAString& aMessageName,
|
||||
const nsAString& aJSONData);
|
||||
|
||||
nsEventStatus DispatchWidgetEvent(WidgetGUIEvent& event);
|
||||
|
||||
void InitializeRootMetrics();
|
||||
|
||||
mozilla::layers::FrameMetrics ProcessUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
|
||||
@ -659,7 +653,6 @@ private:
|
||||
bool mPendingTouchPreventedResponse;
|
||||
ScrollableLayerGuid mPendingTouchPreventedGuid;
|
||||
uint64_t mPendingTouchPreventedBlockId;
|
||||
void FireSingleTapEvent(LayoutDevicePoint aPoint);
|
||||
|
||||
bool mTouchEndCancelled;
|
||||
bool mEndTouchIsClick;
|
||||
|
@ -182,7 +182,9 @@ ToMediaKeyStatus(GMPMediaKeyStatus aStatus) {
|
||||
switch (aStatus) {
|
||||
case kGMPUsable: return MediaKeyStatus::Usable;
|
||||
case kGMPExpired: return MediaKeyStatus::Expired;
|
||||
case kGMPOutputDownscaled: return MediaKeyStatus::Output_downscaled;
|
||||
case kGMPOutputNotAllowed: return MediaKeyStatus::Output_not_allowed;
|
||||
case kGMPInternalError: return MediaKeyStatus::Internal_error;
|
||||
default: return MediaKeyStatus::Internal_error;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
Name: fake
|
||||
Description: Fake GMP Plugin
|
||||
Version: 1.0
|
||||
APIs: encode-video[h264], decode-video[h264], eme-decrypt-v5[fake]
|
||||
APIs: encode-video[h264], decode-video[h264], eme-decrypt-v6[fake]
|
||||
Libraries: dxva2.dll
|
||||
|
@ -79,9 +79,11 @@ enum GMPSessionMessageType {
|
||||
enum GMPMediaKeyStatus {
|
||||
kGMPUsable = 0,
|
||||
kGMPExpired = 1,
|
||||
kGMPOutputNotAllowed = 2,
|
||||
kGMPUnknown = 3,
|
||||
kGMPMediaKeyStatusInvalid = 4 // Must always be last.
|
||||
kGMPOutputDownscaled = 2,
|
||||
kGMPOutputNotAllowed = 3,
|
||||
kGMPInternalError = 4,
|
||||
kGMPUnknown = 5,
|
||||
kGMPMediaKeyStatusInvalid = 6 // Must always be last.
|
||||
};
|
||||
|
||||
// Time in milliseconds, as offset from epoch, 1 Jan 1970.
|
||||
@ -222,7 +224,7 @@ enum GMPSessionType {
|
||||
kGMPSessionInvalid = 2 // Must always be last.
|
||||
};
|
||||
|
||||
#define GMP_API_DECRYPTOR "eme-decrypt-v5"
|
||||
#define GMP_API_DECRYPTOR "eme-decrypt-v6"
|
||||
|
||||
// API exposed by plugin library to manage decryption sessions.
|
||||
// When the Host requests this by calling GMPGetAPIFunc().
|
||||
|
@ -1906,8 +1906,7 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, NPObject *npobj)
|
||||
|
||||
// No existing JSObject, create one.
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, js::Jsvalify(&sNPObjectJSWrapperClass),
|
||||
JS::NullPtr(), JS::NullPtr()));
|
||||
JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, js::Jsvalify(&sNPObjectJSWrapperClass)));
|
||||
|
||||
if (generation != sNPObjWrappers.Generation()) {
|
||||
// Reload entry if the JS_NewObject call caused a GC and reallocated
|
||||
@ -2076,7 +2075,7 @@ CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj,
|
||||
// during initialization.
|
||||
memset(memberPrivate, 0, sizeof(NPObjectMemberPrivate));
|
||||
|
||||
JSObject *memobj = ::JS_NewObject(cx, &sNPObjectMemberClass, JS::NullPtr(), JS::NullPtr());
|
||||
JSObject *memobj = ::JS_NewObject(cx, &sNPObjectMemberClass);
|
||||
if (!memobj) {
|
||||
PR_Free(memberPrivate);
|
||||
return false;
|
||||
|
@ -4,7 +4,9 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "APZCCallbackHelper.h"
|
||||
|
||||
#include "gfxPlatform.h" // For gfxPlatform::UseTiling
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsIDOMElement.h"
|
||||
@ -13,9 +15,14 @@
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
|
||||
#define APZCCH_LOG(...)
|
||||
// #define APZCCH_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__)
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using dom::TabParent;
|
||||
|
||||
bool
|
||||
APZCCallbackHelper::HasValidPresShellId(nsIDOMWindowUtils* aUtils,
|
||||
const FrameMetrics& aMetrics)
|
||||
@ -360,5 +367,67 @@ APZCCallbackHelper::ApplyCallbackTransform(const nsIntPoint& aPoint,
|
||||
return nsIntPoint(ret.x, ret.y);
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
APZCCallbackHelper::DispatchWidgetEvent(WidgetGUIEvent& aEvent)
|
||||
{
|
||||
if (!aEvent.widget)
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
|
||||
// A nested process may be capturing events.
|
||||
if (TabParent* capturer = TabParent::GetEventCapturer()) {
|
||||
if (capturer->TryCapture(aEvent)) {
|
||||
// Only touch events should be captured, and touch events from a parent
|
||||
// process should not make it here. Capture for those is done elsewhere
|
||||
// (for gonk, in nsWindow::DispatchTouchInputViaAPZ).
|
||||
MOZ_ASSERT(!XRE_IsParentProcess());
|
||||
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
}
|
||||
nsEventStatus status;
|
||||
NS_ENSURE_SUCCESS(aEvent.widget->DispatchEvent(&aEvent, status),
|
||||
nsEventStatus_eConsumeNoDefault);
|
||||
return status;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
APZCCallbackHelper::DispatchSynthesizedMouseEvent(uint32_t aMsg,
|
||||
uint64_t aTime,
|
||||
const LayoutDevicePoint& aRefPoint,
|
||||
nsIWidget* aWidget)
|
||||
{
|
||||
MOZ_ASSERT(aMsg == NS_MOUSE_MOVE || aMsg == NS_MOUSE_BUTTON_DOWN ||
|
||||
aMsg == NS_MOUSE_BUTTON_UP || aMsg == NS_MOUSE_MOZLONGTAP);
|
||||
|
||||
WidgetMouseEvent event(true, aMsg, nullptr,
|
||||
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
|
||||
event.refPoint = LayoutDeviceIntPoint(aRefPoint.x, aRefPoint.y);
|
||||
event.time = aTime;
|
||||
event.button = WidgetMouseEvent::eLeftButton;
|
||||
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
event.ignoreRootScrollFrame = true;
|
||||
if (aMsg != NS_MOUSE_MOVE) {
|
||||
event.clickCount = 1;
|
||||
}
|
||||
event.widget = aWidget;
|
||||
|
||||
return DispatchWidgetEvent(event);
|
||||
}
|
||||
|
||||
void
|
||||
APZCCallbackHelper::FireSingleTapEvent(const LayoutDevicePoint& aPoint,
|
||||
nsIWidget* aWidget)
|
||||
{
|
||||
if (aWidget->Destroyed()) {
|
||||
return;
|
||||
}
|
||||
APZCCH_LOG("Dispatching single-tap component events to %s\n",
|
||||
Stringify(aPoint).c_str());
|
||||
int time = 0;
|
||||
DispatchSynthesizedMouseEvent(NS_MOUSE_MOVE, time, aPoint, aWidget);
|
||||
DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_DOWN, time, aPoint, aWidget);
|
||||
DispatchSynthesizedMouseEvent(NS_MOUSE_BUTTON_UP, time, aPoint, aWidget);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,12 @@
|
||||
#define mozilla_layers_APZCCallbackHelper_h
|
||||
|
||||
#include "FrameMetrics.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "nsIDOMWindowUtils.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIWidget;
|
||||
template<class T> struct already_AddRefed;
|
||||
|
||||
namespace mozilla {
|
||||
@ -104,6 +106,23 @@ public:
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
const CSSToLayoutDeviceScale& aScale,
|
||||
float aPresShellResolution);
|
||||
|
||||
/* Dispatch a widget event via the widget stored in the event, if any.
|
||||
* In a child process, allows the TabParent event-capture mechanism to
|
||||
* intercept the event. */
|
||||
static nsEventStatus DispatchWidgetEvent(WidgetGUIEvent& aEvent);
|
||||
|
||||
/* Synthesize a mouse event with the given parameters, and dispatch it
|
||||
* via the given widget. */
|
||||
static nsEventStatus DispatchSynthesizedMouseEvent(uint32_t aMsg,
|
||||
uint64_t aTime,
|
||||
const LayoutDevicePoint& aRefPoint,
|
||||
nsIWidget* aWidget);
|
||||
|
||||
/* Fire a single-tap event at the given point. The event is dispatched
|
||||
* via the given widget. */
|
||||
static void FireSingleTapEvent(const LayoutDevicePoint& aPoint,
|
||||
nsIWidget* aWidget);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -97,3 +97,31 @@ ChromeProcessController::Destroy()
|
||||
MOZ_ASSERT(MessageLoop::current() == mUILoop);
|
||||
mWidget = nullptr;
|
||||
}
|
||||
|
||||
float
|
||||
ChromeProcessController::GetPresShellResolution() const
|
||||
{
|
||||
// The document in the chrome process cannot be zoomed, so its pres shell
|
||||
// resolution is 1.
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::HandleSingleTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
if (MessageLoop::current() != mUILoop) {
|
||||
mUILoop->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &ChromeProcessController::HandleSingleTap,
|
||||
aPoint, aModifiers, aGuid));
|
||||
return;
|
||||
}
|
||||
|
||||
LayoutDevicePoint point =
|
||||
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
|
||||
* mWidget->GetDefaultScale();
|
||||
|
||||
APZCCallbackHelper::FireSingleTapEvent(point, mWidget);
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
virtual void HandleDoubleTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE {}
|
||||
virtual void HandleSingleTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE {}
|
||||
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
|
||||
virtual void HandleLongTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
uint64_t aInputBlockId) MOZ_OVERRIDE {}
|
||||
@ -52,6 +52,7 @@ private:
|
||||
MessageLoop* mUILoop;
|
||||
|
||||
void InitializeRoot();
|
||||
float GetPresShellResolution() const;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -614,16 +614,11 @@ RasterImage::IsOpaque()
|
||||
void
|
||||
RasterImage::OnSurfaceDiscarded()
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &RasterImage::OnSurfaceDiscarded);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mProgressTracker);
|
||||
|
||||
if (mProgressTracker) {
|
||||
mProgressTracker->OnDiscard();
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(mProgressTracker, &ProgressTracker::OnDiscard);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
@ -362,7 +362,7 @@ public:
|
||||
SurfaceCacheImpl(uint32_t aSurfaceCacheExpirationTimeMS,
|
||||
uint32_t aSurfaceCacheDiscardFactor,
|
||||
uint32_t aSurfaceCacheSize)
|
||||
: mExpirationTracker(this, aSurfaceCacheExpirationTimeMS)
|
||||
: mExpirationTracker(aSurfaceCacheExpirationTimeMS)
|
||||
, mMemoryPressureObserver(new MemoryPressureObserver)
|
||||
, mMutex("SurfaceCache")
|
||||
, mDiscardFactor(aSurfaceCacheDiscardFactor)
|
||||
@ -742,6 +742,8 @@ public:
|
||||
nsISupports* aData,
|
||||
bool aAnonymize) MOZ_OVERRIDE
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
// We have explicit memory reporting for the surface cache which is more
|
||||
// accurate than the cost metrics we report here, but these metrics are
|
||||
// still useful to report, since they control the cache's behavior.
|
||||
@ -809,21 +811,18 @@ private:
|
||||
|
||||
struct SurfaceTracker : public nsExpirationTracker<CachedSurface, 2>
|
||||
{
|
||||
SurfaceTracker(SurfaceCacheImpl* aCache, uint32_t aSurfaceCacheExpirationTimeMS)
|
||||
explicit SurfaceTracker(uint32_t aSurfaceCacheExpirationTimeMS)
|
||||
: nsExpirationTracker<CachedSurface, 2>(aSurfaceCacheExpirationTimeMS)
|
||||
, mCache(aCache)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
virtual void NotifyExpired(CachedSurface* aSurface) MOZ_OVERRIDE
|
||||
{
|
||||
if (mCache) {
|
||||
mCache->Remove(aSurface);
|
||||
if (sInstance) {
|
||||
MutexAutoLock lock(sInstance->GetMutex());
|
||||
sInstance->Remove(aSurface);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SurfaceCacheImpl* const mCache; // Weak pointer to owner.
|
||||
};
|
||||
|
||||
struct MemoryPressureObserver : public nsIObserver
|
||||
@ -835,6 +834,7 @@ private:
|
||||
const char16_t*) MOZ_OVERRIDE
|
||||
{
|
||||
if (sInstance && strcmp(aTopic, "memory-pressure") == 0) {
|
||||
MutexAutoLock lock(sInstance->GetMutex());
|
||||
sInstance->DiscardForMemoryPressure();
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -27,18 +27,6 @@ function currentRequest() {
|
||||
return img.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
|
||||
}
|
||||
|
||||
function attachDiscardObserver(result) {
|
||||
// Create the discard observer.
|
||||
let observer = new ImageDiscardObserver(result);
|
||||
let scriptedObserver = Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(Ci.imgITools)
|
||||
.createScriptedObserver(observer);
|
||||
|
||||
// Clone the current imgIRequest with our new observer.
|
||||
let request = currentRequest();
|
||||
return request.clone(scriptedObserver);
|
||||
}
|
||||
|
||||
function isImgDecoded() {
|
||||
let request = currentRequest();
|
||||
return request.imageStatus & Ci.imgIRequest.STATUS_FRAME_COMPLETE ? true : false;
|
||||
@ -69,9 +57,18 @@ function test() {
|
||||
}
|
||||
|
||||
function step2() {
|
||||
// Attach a discard listener and create a place to hold the result.
|
||||
// Create a place to hold the result.
|
||||
var result = { wasDiscarded: false };
|
||||
var clonedRequest = attachDiscardObserver(result);
|
||||
|
||||
// Create the discard observer.
|
||||
var observer = new ImageDiscardObserver(result);
|
||||
var scriptedObserver = Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(Ci.imgITools)
|
||||
.createScriptedObserver(observer);
|
||||
|
||||
// Clone the current imgIRequest with our new observer.
|
||||
var request = currentRequest();
|
||||
var clonedRequest = request.clone(scriptedObserver);
|
||||
|
||||
// Check that the image is decoded.
|
||||
forceDecodeImg();
|
||||
@ -83,6 +80,19 @@ function step2() {
|
||||
var os = Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(Ci.nsIObserverService);
|
||||
os.notifyObservers(null, 'memory-pressure', 'heap-minimize');
|
||||
|
||||
// The discard notification is delivered asynchronously, so pump the event
|
||||
// loop before checking.
|
||||
window.addEventListener('message', function (event) {
|
||||
if (event.data == 'step3') {
|
||||
step3(result, scriptedObserver, clonedRequest);
|
||||
}
|
||||
}, false);
|
||||
|
||||
window.postMessage('step3', '*');
|
||||
}
|
||||
|
||||
function step3(result, scriptedObserver, clonedRequest) {
|
||||
ok(result.wasDiscarded, 'Image should be discarded.');
|
||||
|
||||
// And we're done.
|
||||
|
@ -1548,7 +1548,7 @@ class CloneBufferObject : public NativeObject {
|
||||
static const Class class_;
|
||||
|
||||
static CloneBufferObject *Create(JSContext *cx) {
|
||||
RootedObject obj(cx, JS_NewObject(cx, Jsvalify(&class_), JS::NullPtr(), JS::NullPtr()));
|
||||
RootedObject obj(cx, JS_NewObject(cx, Jsvalify(&class_)));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
obj->as<CloneBufferObject>().setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
|
||||
|
@ -1700,7 +1700,7 @@ TypedObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
return obj_lookupElement(cx, obj, index, objp, propp);
|
||||
|
||||
if (JSID_IS_ATOM(id, cx->names().length)) {
|
||||
MarkNonNativePropertyFound(propp);
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
@ -1712,7 +1712,7 @@ TypedObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
StructTypeDescr &structDescr = descr->as<StructTypeDescr>();
|
||||
size_t index;
|
||||
if (structDescr.fieldIndex(id, &index)) {
|
||||
MarkNonNativePropertyFound(propp);
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
@ -1746,7 +1746,7 @@ TypedObject::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
{
|
||||
MOZ_ASSERT(obj->is<TypedObject>());
|
||||
MarkNonNativePropertyFound(propp);
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
@ -909,7 +909,7 @@ InitCTypeClass(JSContext* cx, HandleObject parent)
|
||||
MOZ_ASSERT(fnproto);
|
||||
|
||||
// Set up ctypes.CType.prototype.
|
||||
RootedObject prototype(cx, JS_NewObject(cx, &sCTypeProtoClass, fnproto, parent));
|
||||
RootedObject prototype(cx, JS_NewObjectWithGivenProto(cx, &sCTypeProtoClass, fnproto, parent));
|
||||
if (!prototype)
|
||||
return nullptr;
|
||||
|
||||
@ -965,7 +965,7 @@ InitCDataClass(JSContext* cx, HandleObject parent, HandleObject CTypeProto)
|
||||
return nullptr;
|
||||
|
||||
// Set up ctypes.CData.prototype.
|
||||
RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, NullPtr(), parent));
|
||||
RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, parent));
|
||||
if (!prototype)
|
||||
return nullptr;
|
||||
|
||||
@ -1029,7 +1029,7 @@ InitTypeConstructor(JSContext* cx,
|
||||
return false;
|
||||
|
||||
// Set up the .prototype and .prototype.constructor properties.
|
||||
typeProto.set(JS_NewObject(cx, &sCTypeProtoClass, CTypeProto, parent));
|
||||
typeProto.set(JS_NewObjectWithGivenProto(cx, &sCTypeProtoClass, CTypeProto, parent));
|
||||
if (!typeProto)
|
||||
return false;
|
||||
|
||||
@ -1056,7 +1056,7 @@ InitTypeConstructor(JSContext* cx,
|
||||
// created from the given type constructor. This has ctypes.CData.prototype
|
||||
// as its prototype, such that it inherits the properties and functions
|
||||
// common to all CDatas.
|
||||
dataProto.set(JS_NewObject(cx, &sCDataProtoClass, CDataProto, parent));
|
||||
dataProto.set(JS_NewObjectWithGivenProto(cx, &sCDataProtoClass, CDataProto, parent));
|
||||
if (!dataProto)
|
||||
return false;
|
||||
|
||||
@ -1363,7 +1363,7 @@ JS_PUBLIC_API(bool)
|
||||
JS_InitCTypesClass(JSContext* cx, HandleObject global)
|
||||
{
|
||||
// attach ctypes property to global object
|
||||
RootedObject ctypes(cx, JS_NewObject(cx, &sCTypesGlobalClass, NullPtr(), NullPtr()));
|
||||
RootedObject ctypes(cx, JS_NewObject(cx, &sCTypesGlobalClass));
|
||||
if (!ctypes)
|
||||
return false;
|
||||
|
||||
@ -1386,7 +1386,7 @@ JS_InitCTypesClass(JSContext* cx, HandleObject global)
|
||||
if (!GetObjectProperty(cx, ctypes, "CDataFinalizer", &ctor))
|
||||
return false;
|
||||
|
||||
RootedObject prototype(cx, JS_NewObject(cx, &sCDataFinalizerProtoClass, NullPtr(), ctypes));
|
||||
RootedObject prototype(cx, JS_NewObject(cx, &sCDataFinalizerProtoClass, ctypes));
|
||||
if (!prototype)
|
||||
return false;
|
||||
|
||||
@ -3301,7 +3301,7 @@ CType::Create(JSContext* cx,
|
||||
// * 'constructor' property === 't'
|
||||
// * Additional properties specified by 'ps', as appropriate for the
|
||||
// specific type instance 't'.
|
||||
RootedObject typeObj(cx, JS_NewObject(cx, &sCTypeClass, typeProto, parent));
|
||||
RootedObject typeObj(cx, JS_NewObjectWithGivenProto(cx, &sCTypeClass, typeProto, parent));
|
||||
if (!typeObj)
|
||||
return nullptr;
|
||||
|
||||
@ -3316,7 +3316,7 @@ CType::Create(JSContext* cx,
|
||||
|
||||
if (dataProto) {
|
||||
// Set up the 'prototype' and 'prototype.constructor' properties.
|
||||
RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, dataProto, parent));
|
||||
RootedObject prototype(cx, JS_NewObjectWithGivenProto(cx, &sCDataProtoClass, dataProto, parent));
|
||||
if (!prototype)
|
||||
return nullptr;
|
||||
|
||||
@ -4868,7 +4868,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb
|
||||
// Set up the 'prototype' and 'prototype.constructor' properties.
|
||||
// The prototype will reflect the struct fields as properties on CData objects
|
||||
// created from this type.
|
||||
RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, dataProto, NullPtr()));
|
||||
RootedObject prototype(cx, JS_NewObjectWithGivenProto(cx, &sCDataProtoClass, dataProto, NullPtr()));
|
||||
if (!prototype)
|
||||
return false;
|
||||
|
||||
@ -6075,7 +6075,7 @@ CClosure::Create(JSContext* cx,
|
||||
RootedValue errVal(cx, errVal_);
|
||||
MOZ_ASSERT(fnObj);
|
||||
|
||||
RootedObject result(cx, JS_NewObject(cx, &sCClosureClass, NullPtr(), NullPtr()));
|
||||
RootedObject result(cx, JS_NewObject(cx, &sCClosureClass));
|
||||
if (!result)
|
||||
return nullptr;
|
||||
|
||||
@ -6377,7 +6377,7 @@ CData::Create(JSContext* cx,
|
||||
RootedObject parent(cx, JS_GetParent(typeObj));
|
||||
MOZ_ASSERT(parent);
|
||||
|
||||
RootedObject dataObj(cx, JS_NewObject(cx, &sCDataClass, proto, parent));
|
||||
RootedObject dataObj(cx, JS_NewObjectWithGivenProto(cx, &sCDataClass, proto, parent));
|
||||
if (!dataObj)
|
||||
return nullptr;
|
||||
|
||||
@ -6958,7 +6958,8 @@ CDataFinalizer::Construct(JSContext* cx, unsigned argc, jsval *vp)
|
||||
|
||||
// Get arguments
|
||||
if (args.length() == 0) { // Special case: the empty (already finalized) object
|
||||
JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NullPtr());
|
||||
JSObject *objResult = JS_NewObjectWithGivenProto(cx, &sCDataFinalizerClass, objProto,
|
||||
NullPtr());
|
||||
args.rval().setObject(*objResult);
|
||||
return true;
|
||||
}
|
||||
@ -7057,7 +7058,7 @@ CDataFinalizer::Construct(JSContext* cx, unsigned argc, jsval *vp)
|
||||
|
||||
// 5. Create |objResult|
|
||||
|
||||
JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NullPtr());
|
||||
JSObject *objResult = JS_NewObjectWithGivenProto(cx, &sCDataFinalizerClass, objProto, NullPtr());
|
||||
if (!objResult) {
|
||||
return false;
|
||||
}
|
||||
@ -7357,7 +7358,7 @@ Int64Base::Construct(JSContext* cx,
|
||||
{
|
||||
const JSClass* clasp = isUnsigned ? &sUInt64Class : &sInt64Class;
|
||||
RootedObject parent(cx, JS_GetParent(proto));
|
||||
RootedObject result(cx, JS_NewObject(cx, clasp, proto, parent));
|
||||
RootedObject result(cx, JS_NewObjectWithGivenProto(cx, clasp, proto, parent));
|
||||
if (!result)
|
||||
return nullptr;
|
||||
|
||||
|
@ -83,8 +83,7 @@ JSObject*
|
||||
Library::Create(JSContext* cx, jsval path_, const JSCTypesCallbacks* callbacks)
|
||||
{
|
||||
RootedValue path(cx, path_);
|
||||
RootedObject libraryObj(cx,
|
||||
JS_NewObject(cx, &sLibraryClass, NullPtr(), NullPtr()));
|
||||
RootedObject libraryObj(cx, JS_NewObject(cx, &sLibraryClass));
|
||||
if (!libraryObj)
|
||||
return nullptr;
|
||||
|
||||
|
17
js/src/jit-test/tests/ion/nursery-getter-setter.js
Normal file
17
js/src/jit-test/tests/ion/nursery-getter-setter.js
Normal file
@ -0,0 +1,17 @@
|
||||
var threshold = getJitCompilerOptions()["ion.warmup.trigger"] + 101;
|
||||
function bar(i) {
|
||||
if (!i)
|
||||
with (this) {}; // Don't inline.
|
||||
if (i === threshold)
|
||||
minorgc();
|
||||
}
|
||||
|
||||
function f() {
|
||||
var o2 = Object.create({get foo() { return this.x; }, set foo(x) { this.x = x + 1; }});
|
||||
for (var i=0; i<2000; i++) {
|
||||
o2.foo = i;
|
||||
assertEq(o2.foo, i + 1);
|
||||
bar(i);
|
||||
}
|
||||
}
|
||||
f();
|
@ -3334,14 +3334,6 @@ IsCacheableGetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *sh
|
||||
return false;
|
||||
|
||||
JSFunction *func = &shape->getterObject()->as<JSFunction>();
|
||||
|
||||
// Information from get prop call ICs may be used directly from Ion code,
|
||||
// and should not be nursery allocated.
|
||||
if (IsInsideNursery(holder) || IsInsideNursery(func)) {
|
||||
*isTemporarilyUnoptimizable = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (func->isNative()) {
|
||||
*isScripted = false;
|
||||
return true;
|
||||
@ -3457,13 +3449,6 @@ IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *sh
|
||||
|
||||
JSFunction *func = &shape->setterObject()->as<JSFunction>();
|
||||
|
||||
// Information from set prop call ICs may be used directly from Ion code,
|
||||
// and should not be nursery allocated.
|
||||
if (IsInsideNursery(holder) || IsInsideNursery(func)) {
|
||||
*isTemporarilyUnoptimizable = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (func->isNative()) {
|
||||
*isScripted = false;
|
||||
return true;
|
||||
|
@ -2154,6 +2154,19 @@ CodeGenerator::visitPointer(LPointer *lir)
|
||||
masm.movePtr(ImmPtr(lir->ptr()), ToRegister(lir->output()));
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitNurseryObject(LNurseryObject *lir)
|
||||
{
|
||||
Register output = ToRegister(lir->output());
|
||||
uint32_t index = lir->mir()->index();
|
||||
|
||||
// Store a dummy JSObject pointer. We will fix it up on the main thread,
|
||||
// in JitCode::fixupNurseryObjects. The low bit is set to distinguish
|
||||
// it from a real JSObject pointer.
|
||||
JSObject *ptr = reinterpret_cast<JSObject*>((uintptr_t(index) << 1) | 1);
|
||||
masm.movePtr(ImmGCPtr(IonNurseryPtr(ptr)), output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitSlots(LSlots *lir)
|
||||
{
|
||||
@ -7383,6 +7396,9 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Replace dummy JSObject pointers embedded by LNurseryObject.
|
||||
code->fixupNurseryObjects(cx, gen->nurseryObjects());
|
||||
|
||||
// The correct state for prebarriers is unknown until the end of compilation,
|
||||
// since a GC can occur during code generation. All barriers are emitted
|
||||
// off-by-default, and are toggled on here if necessary.
|
||||
|
@ -111,6 +111,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
void visitLambdaArrow(LLambdaArrow *lir);
|
||||
void visitLambdaForSingleton(LLambdaForSingleton *lir);
|
||||
void visitPointer(LPointer *lir);
|
||||
void visitNurseryObject(LNurseryObject *lir);
|
||||
void visitSlots(LSlots *lir);
|
||||
void visitLoadSlotT(LLoadSlotT *lir);
|
||||
void visitLoadSlotV(LLoadSlotV *lir);
|
||||
|
@ -163,7 +163,8 @@ JitRuntime::JitRuntime()
|
||||
osrTempData_(nullptr),
|
||||
mutatingBackedgeList_(false),
|
||||
ionReturnOverride_(MagicValue(JS_ARG_POISON)),
|
||||
jitcodeGlobalTable_(nullptr)
|
||||
jitcodeGlobalTable_(nullptr),
|
||||
hasIonNurseryObjects_(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -653,6 +654,17 @@ JitCode::trace(JSTracer *trc)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JitCode::fixupNurseryObjects(JSContext *cx, const ObjectVector &nurseryObjects)
|
||||
{
|
||||
if (nurseryObjects.empty() || !dataRelocTableBytes_)
|
||||
return;
|
||||
|
||||
uint8_t *start = code_ + dataRelocTableOffset();
|
||||
CompactBufferReader reader(start, start + dataRelocTableBytes_);
|
||||
MacroAssembler::FixupNurseryObjects(cx, this, reader, nurseryObjects);
|
||||
}
|
||||
|
||||
void
|
||||
JitCode::finalize(FreeOp *fop)
|
||||
{
|
||||
@ -1671,6 +1683,62 @@ AttachFinishedCompilations(JSContext *cx)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MIRGenerator::traceNurseryObjects(JSTracer *trc)
|
||||
{
|
||||
MarkObjectRootRange(trc, nurseryObjects_.length(), nurseryObjects_.begin(), "ion-nursery-objects");
|
||||
}
|
||||
|
||||
class MarkOffThreadNurseryObjects : public gc::BufferableRef
|
||||
{
|
||||
public:
|
||||
void mark(JSTracer *trc);
|
||||
};
|
||||
|
||||
void
|
||||
MarkOffThreadNurseryObjects::mark(JSTracer *trc)
|
||||
{
|
||||
JSRuntime *rt = trc->runtime();
|
||||
|
||||
MOZ_ASSERT(rt->jitRuntime()->hasIonNurseryObjects());
|
||||
rt->jitRuntime()->setHasIonNurseryObjects(false);
|
||||
|
||||
AutoLockHelperThreadState lock;
|
||||
if (!HelperThreadState().threads)
|
||||
return;
|
||||
|
||||
// Trace nursery objects of any builders which haven't started yet.
|
||||
GlobalHelperThreadState::IonBuilderVector &worklist = HelperThreadState().ionWorklist();
|
||||
for (size_t i = 0; i < worklist.length(); i++) {
|
||||
jit::IonBuilder *builder = worklist[i];
|
||||
if (builder->script()->runtimeFromAnyThread() == rt)
|
||||
builder->traceNurseryObjects(trc);
|
||||
}
|
||||
|
||||
// Trace nursery objects of in-progress entries.
|
||||
for (size_t i = 0; i < HelperThreadState().threadCount; i++) {
|
||||
HelperThread &helper = HelperThreadState().threads[i];
|
||||
if (helper.ionBuilder && helper.ionBuilder->script()->runtimeFromAnyThread() == rt)
|
||||
helper.ionBuilder->traceNurseryObjects(trc);
|
||||
}
|
||||
|
||||
// Trace nursery objects of any completed entries.
|
||||
GlobalHelperThreadState::IonBuilderVector &finished = HelperThreadState().ionFinishedList();
|
||||
for (size_t i = 0; i < finished.length(); i++) {
|
||||
jit::IonBuilder *builder = finished[i];
|
||||
if (builder->script()->runtimeFromAnyThread() == rt)
|
||||
builder->traceNurseryObjects(trc);
|
||||
}
|
||||
|
||||
// Trace nursery objects of lazy-linked builders.
|
||||
jit::IonBuilder *builder = HelperThreadState().ionLazyLinkList().getFirst();
|
||||
while (builder) {
|
||||
if (builder->script()->runtimeFromAnyThread() == rt)
|
||||
builder->traceNurseryObjects(trc);
|
||||
builder = builder->getNext();
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
OffThreadCompilationAvailable(JSContext *cx)
|
||||
{
|
||||
@ -1866,6 +1934,15 @@ IonCompile(JSContext *cx, JSScript *script,
|
||||
JitSpew(JitSpew_IonLogs, "Can't log script %s:%d. (Compiled on background thread.)",
|
||||
builderScript->filename(), builderScript->lineno());
|
||||
|
||||
JSRuntime *rt = cx->runtime();
|
||||
if (!builder->nurseryObjects().empty() && !rt->jitRuntime()->hasIonNurseryObjects()) {
|
||||
// Ensure the builder's nursery objects are marked when a nursery
|
||||
// GC happens on the main thread.
|
||||
MarkOffThreadNurseryObjects mark;
|
||||
rt->gc.storeBuffer.putGeneric(mark);
|
||||
rt->jitRuntime()->setHasIonNurseryObjects(true);
|
||||
}
|
||||
|
||||
if (!StartOffThreadIonCompile(cx, builder)) {
|
||||
JitSpew(JitSpew_IonAbort, "Unable to start off-thread ion compilation.");
|
||||
return AbortReason_Alloc;
|
||||
|
@ -216,6 +216,37 @@ IonBuilder::spew(const char *message)
|
||||
#endif
|
||||
}
|
||||
|
||||
MInstruction *
|
||||
IonBuilder::constantMaybeNursery(JSObject *obj)
|
||||
{
|
||||
MOZ_ASSERT(obj);
|
||||
if (!IsInsideNursery(obj))
|
||||
return constant(ObjectValue(*obj));
|
||||
|
||||
// If |obj| is in the nursery, we have to add it to the list of nursery
|
||||
// objects that get traced during off-thread compilation. We use
|
||||
// MNurseryObject to ensure we will patch the code with the right
|
||||
// pointer after codegen is done.
|
||||
|
||||
size_t index = UINT32_MAX;
|
||||
for (size_t i = 0, len = nurseryObjects_.length(); i < len; i++) {
|
||||
if (nurseryObjects_[i] == obj) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == UINT32_MAX) {
|
||||
if (!nurseryObjects_.append(obj))
|
||||
return nullptr;
|
||||
index = nurseryObjects_.length() - 1;
|
||||
}
|
||||
|
||||
MNurseryObject *ins = MNurseryObject::New(alloc(), obj, index, constraints());
|
||||
current->add(ins);
|
||||
return ins;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
GetJumpOffset(jsbytecode *pc)
|
||||
{
|
||||
@ -5838,6 +5869,9 @@ bool
|
||||
IonBuilder::testShouldDOMCall(types::TypeSet *inTypes,
|
||||
JSFunction *func, JSJitInfo::OpType opType)
|
||||
{
|
||||
if (IsInsideNursery(func))
|
||||
return false;
|
||||
|
||||
if (!func->isNative() || !func->jitInfo())
|
||||
return false;
|
||||
|
||||
@ -9297,9 +9331,7 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
||||
}
|
||||
}
|
||||
|
||||
if (!type->hasTenuredProto())
|
||||
return false;
|
||||
JSObject *proto = type->proto().toObjectOrNull();
|
||||
JSObject *proto = type->protoMaybeInNursery().toObjectOrNull();
|
||||
if (proto == foundProto)
|
||||
break;
|
||||
if (!proto) {
|
||||
@ -9307,7 +9339,7 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
||||
// object's prototype chain.
|
||||
return false;
|
||||
}
|
||||
type = types::TypeObjectKey::get(type->proto().toObjectOrNull());
|
||||
type = types::TypeObjectKey::get(proto);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9336,14 +9368,14 @@ IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, P
|
||||
// Don't mark the proto. It will be held down by the shape
|
||||
// guard. This allows us to use properties found on prototypes
|
||||
// with properties unknown to TI.
|
||||
if (type->proto() == TaggedProto(foundProto))
|
||||
if (type->protoMaybeInNursery() == TaggedProto(foundProto))
|
||||
break;
|
||||
type = types::TypeObjectKey::get(type->proto().toObjectOrNull());
|
||||
type = types::TypeObjectKey::get(type->protoMaybeInNursery().toObjectOrNull());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
bool
|
||||
IonBuilder::testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
bool isGetter, JSObject *foundProto, Shape *lastProperty,
|
||||
MDefinition **guard,
|
||||
@ -9385,7 +9417,7 @@ IonBuilder::testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName
|
||||
return true;
|
||||
}
|
||||
|
||||
MInstruction *wrapper = constant(ObjectValue(*foundProto));
|
||||
MInstruction *wrapper = constantMaybeNursery(foundProto);
|
||||
*guard = addShapeGuard(wrapper, lastProperty, Bailout_ShapeGuard);
|
||||
return true;
|
||||
}
|
||||
@ -10049,7 +10081,7 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
|
||||
// Make sure there's enough room
|
||||
if (!current->ensureHasSlots(2))
|
||||
return false;
|
||||
pushConstant(ObjectValue(*commonGetter));
|
||||
current->push(constantMaybeNursery(commonGetter));
|
||||
|
||||
current->push(obj);
|
||||
|
||||
@ -10089,7 +10121,8 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
|
||||
}
|
||||
}
|
||||
|
||||
if (!makeCall(commonGetter, callInfo, false))
|
||||
JSFunction *tenuredCommonGetter = IsInsideNursery(commonGetter) ? nullptr : commonGetter;
|
||||
if (!makeCall(tenuredCommonGetter, callInfo, false))
|
||||
return false;
|
||||
|
||||
// If the getter could have been inlined, don't track success. The call to
|
||||
@ -10497,8 +10530,7 @@ IonBuilder::setPropTryCommonSetter(bool *emitted, MDefinition *obj,
|
||||
if (!current->ensureHasSlots(3))
|
||||
return false;
|
||||
|
||||
pushConstant(ObjectValue(*commonSetter));
|
||||
|
||||
current->push(constantMaybeNursery(commonSetter));
|
||||
current->push(obj);
|
||||
current->push(value);
|
||||
|
||||
@ -10528,7 +10560,8 @@ IonBuilder::setPropTryCommonSetter(bool *emitted, MDefinition *obj,
|
||||
}
|
||||
}
|
||||
|
||||
MCall *call = makeCallHelper(commonSetter, callInfo, false);
|
||||
JSFunction *tenuredCommonSetter = IsInsideNursery(commonSetter) ? nullptr : commonSetter;
|
||||
MCall *call = makeCallHelper(tenuredCommonSetter, callInfo, false);
|
||||
if (!call)
|
||||
return false;
|
||||
|
||||
|
@ -238,6 +238,8 @@ class IonBuilder
|
||||
void trackActionableAbort(const char *message);
|
||||
void spew(const char *message);
|
||||
|
||||
MInstruction *constantMaybeNursery(JSObject *obj);
|
||||
|
||||
JSFunction *getSingleCallTarget(types::TemporaryTypeSet *calleeTypes);
|
||||
bool getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
|
||||
ObjectVector &targets, uint32_t maxTargets);
|
||||
|
@ -1177,9 +1177,17 @@ CanAttachNativeGetProp(typename GetPropCache::Context cx, const GetPropCache &ca
|
||||
// of turn. We don't mind doing this even when purity isn't required, because we
|
||||
// only miss out on shape hashification, which is only a temporary perf cost.
|
||||
// The limits were arbitrarily set, anyways.
|
||||
if (!LookupPropertyPure(cx, obj, NameToId(name), holder.address(), shape.address()))
|
||||
JSObject *baseHolder = nullptr;
|
||||
if (!LookupPropertyPure(cx, obj, NameToId(name), &baseHolder, shape.address()))
|
||||
return GetPropertyIC::CanAttachNone;
|
||||
|
||||
MOZ_ASSERT(!holder);
|
||||
if (baseHolder) {
|
||||
if (!baseHolder->isNative())
|
||||
return GetPropertyIC::CanAttachNone;
|
||||
holder.set(&baseHolder->as<NativeObject>());
|
||||
}
|
||||
|
||||
RootedScript script(cx);
|
||||
jsbytecode *pc;
|
||||
cache.getScriptedLocation(&script, &pc);
|
||||
@ -2645,7 +2653,7 @@ IsPropertyAddInlineable(NativeObject *obj, HandleId id, ConstantOrRegister val,
|
||||
|
||||
static SetPropertyIC::NativeSetPropCacheability
|
||||
CanAttachNativeSetProp(JSContext *cx, HandleObject obj, HandleId id, ConstantOrRegister val,
|
||||
bool needsTypeBarrier, MutableHandleNativeObject holder,
|
||||
bool needsTypeBarrier, MutableHandleObject holder,
|
||||
MutableHandleShape shape, bool *checkTypeset)
|
||||
{
|
||||
if (!obj->isNative())
|
||||
@ -2723,7 +2731,7 @@ SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
|
||||
}
|
||||
|
||||
RootedShape shape(cx);
|
||||
RootedNativeObject holder(cx);
|
||||
RootedObject holder(cx);
|
||||
bool checkTypeset;
|
||||
canCache = CanAttachNativeSetProp(cx, obj, id, cache.value(), cache.needsTypeBarrier(),
|
||||
&holder, &shape, &checkTypeset);
|
||||
|
@ -32,6 +32,8 @@ class CodeOffsetLabel;
|
||||
class PatchableBackedge;
|
||||
class IonBuilder;
|
||||
|
||||
typedef Vector<JSObject *, 4, JitAllocPolicy> ObjectVector;
|
||||
|
||||
class JitCode : public gc::TenuredCell
|
||||
{
|
||||
protected:
|
||||
@ -112,6 +114,8 @@ class JitCode : public gc::TenuredCell
|
||||
invalidated_ = true;
|
||||
}
|
||||
|
||||
void fixupNurseryObjects(JSContext *cx, const ObjectVector &nurseryObjects);
|
||||
|
||||
void setHasBytecodeMap() {
|
||||
hasBytecodeMap_ = true;
|
||||
}
|
||||
|
@ -235,6 +235,8 @@ class JitRuntime
|
||||
// Global table of jitcode native address => bytecode address mappings.
|
||||
JitcodeGlobalTable *jitcodeGlobalTable_;
|
||||
|
||||
bool hasIonNurseryObjects_;
|
||||
|
||||
private:
|
||||
JitCode *generateLazyLinkStub(JSContext *cx);
|
||||
JitCode *generateProfilerExitFrameTailStub(JSContext *cx);
|
||||
@ -390,6 +392,13 @@ class JitRuntime
|
||||
ionReturnOverride_ = v;
|
||||
}
|
||||
|
||||
bool hasIonNurseryObjects() const {
|
||||
return hasIonNurseryObjects_;
|
||||
}
|
||||
void setHasIonNurseryObjects(bool b) {
|
||||
hasIonNurseryObjects_ = b;
|
||||
}
|
||||
|
||||
bool hasJitcodeGlobalTable() const {
|
||||
return jitcodeGlobalTable_ != nullptr;
|
||||
}
|
||||
|
@ -683,6 +683,16 @@ class LValue : public LInstructionHelper<BOX_PIECES, 0, 0>
|
||||
}
|
||||
};
|
||||
|
||||
class LNurseryObject : public LInstructionHelper<1, 0, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(NurseryObject);
|
||||
|
||||
MNurseryObject *mir() const {
|
||||
return mir_->toNurseryObject();
|
||||
}
|
||||
};
|
||||
|
||||
// Clone an object literal such as we are not modifying the object contained in
|
||||
// the sources.
|
||||
class LCloneLiteral : public LCallInstructionHelper<1, 1, 0>
|
||||
|
@ -335,6 +335,7 @@
|
||||
_(AssertRangeV) \
|
||||
_(LexicalCheck) \
|
||||
_(ThrowUninitializedLexical) \
|
||||
_(NurseryObject) \
|
||||
_(Debugger)
|
||||
|
||||
#if defined(JS_CODEGEN_X86)
|
||||
|
@ -4003,6 +4003,12 @@ LIRGenerator::visitDebugger(MDebugger *ins)
|
||||
add(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitNurseryObject(MNurseryObject *ins)
|
||||
{
|
||||
define(new(alloc()) LNurseryObject(), ins);
|
||||
}
|
||||
|
||||
static void
|
||||
SpewResumePoint(MBasicBlock *block, MInstruction *ins, MResumePoint *resumePoint)
|
||||
{
|
||||
|
@ -287,6 +287,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
void visitLexicalCheck(MLexicalCheck *ins);
|
||||
void visitThrowUninitializedLexical(MThrowUninitializedLexical *ins);
|
||||
void visitDebugger(MDebugger *ins);
|
||||
void visitNurseryObject(MNurseryObject *ins);
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
@ -676,6 +676,7 @@ MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constra
|
||||
if (vp.isObject()) {
|
||||
// Create a singleton type set for the object. This isn't necessary for
|
||||
// other types as the result type encodes all needed information.
|
||||
MOZ_ASSERT(!IsInsideNursery(&vp.toObject()));
|
||||
setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject()));
|
||||
}
|
||||
if (vp.isMagic() && vp.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
|
||||
@ -695,6 +696,7 @@ MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constra
|
||||
MConstant::MConstant(JSObject *obj)
|
||||
: value_(ObjectValue(*obj))
|
||||
{
|
||||
MOZ_ASSERT(!IsInsideNursery(obj));
|
||||
setResultType(MIRType_Object);
|
||||
setMovable();
|
||||
}
|
||||
@ -804,6 +806,39 @@ MConstant::canProduceFloat32() const
|
||||
return true;
|
||||
}
|
||||
|
||||
MNurseryObject::MNurseryObject(JSObject *obj, uint32_t index, types::CompilerConstraintList *constraints)
|
||||
: index_(index)
|
||||
{
|
||||
setResultType(MIRType_Object);
|
||||
|
||||
MOZ_ASSERT(IsInsideNursery(obj));
|
||||
MOZ_ASSERT(!obj->hasSingletonType());
|
||||
setResultTypeSet(MakeSingletonTypeSet(constraints, obj));
|
||||
|
||||
setMovable();
|
||||
}
|
||||
|
||||
MNurseryObject *
|
||||
MNurseryObject::New(TempAllocator &alloc, JSObject *obj, uint32_t index,
|
||||
types::CompilerConstraintList *constraints)
|
||||
{
|
||||
return new(alloc) MNurseryObject(obj, index, constraints);
|
||||
}
|
||||
|
||||
HashNumber
|
||||
MNurseryObject::valueHash() const
|
||||
{
|
||||
return HashNumber(index_);
|
||||
}
|
||||
|
||||
bool
|
||||
MNurseryObject::congruentTo(const MDefinition *ins) const
|
||||
{
|
||||
if (!ins->isNurseryObject())
|
||||
return false;
|
||||
return ins->toNurseryObject()->index_ == index_;
|
||||
}
|
||||
|
||||
MDefinition*
|
||||
MSimdValueX4::foldsTo(TempAllocator &alloc)
|
||||
{
|
||||
|
@ -1329,6 +1329,33 @@ class MConstant : public MNullaryInstruction
|
||||
ALLOW_CLONE(MConstant)
|
||||
};
|
||||
|
||||
class MNurseryObject : public MNullaryInstruction
|
||||
{
|
||||
// Index in MIRGenerator::nurseryObjects_.
|
||||
uint32_t index_;
|
||||
|
||||
protected:
|
||||
MNurseryObject(JSObject *obj, uint32_t index, types::CompilerConstraintList *constraints);
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(NurseryObject)
|
||||
static MNurseryObject *New(TempAllocator &alloc, JSObject *obj, uint32_t index,
|
||||
types::CompilerConstraintList *constraints = nullptr);
|
||||
|
||||
HashNumber valueHash() const MOZ_OVERRIDE;
|
||||
bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE;
|
||||
|
||||
uint32_t index() const {
|
||||
return index_;
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const MOZ_OVERRIDE {
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
||||
ALLOW_CLONE(MNurseryObject)
|
||||
};
|
||||
|
||||
// Generic constructor of SIMD valuesX4.
|
||||
class MSimdValueX4
|
||||
: public MQuaternaryInstruction,
|
||||
@ -9825,7 +9852,7 @@ class MGuardObjectIdentity
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data
|
||||
{
|
||||
AlwaysTenured<JSObject *> singleObject_;
|
||||
AlwaysTenuredObject singleObject_;
|
||||
bool bailOnEquality_;
|
||||
|
||||
MGuardObjectIdentity(MDefinition *obj, JSObject *singleObject, bool bailOnEquality)
|
||||
|
@ -193,6 +193,12 @@ class MIRGenerator
|
||||
bool instrumentedProfiling_;
|
||||
bool instrumentedProfilingIsCached_;
|
||||
|
||||
// List of nursery objects used by this compilation. Can be traced by a
|
||||
// minor GC while compilation happens off-thread. This Vector should only
|
||||
// be accessed on the main thread (IonBuilder, nursery GC or
|
||||
// CodeGenerator::link).
|
||||
ObjectVector nurseryObjects_;
|
||||
|
||||
void addAbortedNewScriptPropertiesType(types::TypeObject *type);
|
||||
void setForceAbort() {
|
||||
shouldForceAbort_ = true;
|
||||
@ -210,6 +216,12 @@ class MIRGenerator
|
||||
|
||||
public:
|
||||
const JitCompileOptions options;
|
||||
|
||||
void traceNurseryObjects(JSTracer *trc);
|
||||
|
||||
const ObjectVector &nurseryObjects() const {
|
||||
return nurseryObjects_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
@ -39,6 +39,7 @@ MIRGenerator::MIRGenerator(CompileCompartment *compartment, const JitCompileOpti
|
||||
modifiesFrameArguments_(false),
|
||||
instrumentedProfiling_(false),
|
||||
instrumentedProfilingIsCached_(false),
|
||||
nurseryObjects_(*alloc),
|
||||
options(options)
|
||||
{ }
|
||||
|
||||
|
@ -12,6 +12,7 @@ namespace jit {
|
||||
|
||||
#define MIR_OPCODE_LIST(_) \
|
||||
_(Constant) \
|
||||
_(NurseryObject) \
|
||||
_(SimdBox) \
|
||||
_(SimdUnbox) \
|
||||
_(SimdValueX4) \
|
||||
|
@ -805,6 +805,12 @@ TraceOneDataRelocation(JSTracer *trc, Iter *iter, MacroAssemblerARM *masm)
|
||||
const void *prior = Assembler::GetPtr32Target(iter, &dest, &rs);
|
||||
void *ptr = const_cast<void *>(prior);
|
||||
|
||||
// The low bit shouldn't be set. If it is, we probably got a dummy
|
||||
// pointer inserted by CodeGenerator::visitNurseryObject, but we
|
||||
// shouldn't be able to trigger GC before those are patched to their
|
||||
// real values.
|
||||
MOZ_ASSERT(!(uintptr_t(ptr) & 0x1));
|
||||
|
||||
// No barrier needed since these are constants.
|
||||
gc::MarkGCThingUnbarriered(trc, &ptr, "ion-masm-ptr");
|
||||
|
||||
@ -846,6 +852,51 @@ Assembler::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReade
|
||||
::TraceDataRelocations(trc, code->raw(), reader, static_cast<MacroAssemblerARM *>(Dummy));
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
|
||||
const ObjectVector &nurseryObjects)
|
||||
{
|
||||
MOZ_ASSERT(!nurseryObjects.empty());
|
||||
|
||||
uint8_t *buffer = code->raw();
|
||||
bool hasNurseryPointers = false;
|
||||
MacroAssemblerARM *masm = static_cast<MacroAssemblerARM *>(Dummy);
|
||||
|
||||
while (reader.more()) {
|
||||
size_t offset = reader.readUnsigned();
|
||||
InstructionIterator iter((Instruction*)(buffer + offset));
|
||||
Instruction *ins = iter.cur();
|
||||
Register dest;
|
||||
Assembler::RelocStyle rs;
|
||||
const void *prior = Assembler::GetPtr32Target(&iter, &dest, &rs);
|
||||
void *ptr = const_cast<void *>(prior);
|
||||
uintptr_t word = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
if (!(word & 0x1))
|
||||
continue;
|
||||
|
||||
uint32_t index = word >> 1;
|
||||
JSObject *obj = nurseryObjects[index];
|
||||
masm->ma_movPatchable(Imm32(int32_t(obj)), dest, Assembler::Always, rs, ins);
|
||||
|
||||
if (rs != Assembler::L_LDR) {
|
||||
// L_LDR won't cause any instructions to be updated.
|
||||
AutoFlushICache::flush(uintptr_t(ins), 4);
|
||||
AutoFlushICache::flush(uintptr_t(ins->next()), 4);
|
||||
}
|
||||
|
||||
// Either all objects are still in the nursery, or all objects are
|
||||
// tenured.
|
||||
MOZ_ASSERT_IF(hasNurseryPointers, IsInsideNursery(obj));
|
||||
|
||||
if (!hasNurseryPointers && IsInsideNursery(obj))
|
||||
hasNurseryPointers = true;
|
||||
}
|
||||
|
||||
if (hasNurseryPointers)
|
||||
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(code);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::copyJumpRelocationTable(uint8_t *dest)
|
||||
{
|
||||
|
@ -1597,6 +1597,9 @@ class Assembler : public AssemblerShared
|
||||
static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
|
||||
static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
|
||||
|
||||
static void FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
|
||||
const ObjectVector &nurseryObjects);
|
||||
|
||||
static bool SupportsFloatingPoint() {
|
||||
return HasVFP();
|
||||
}
|
||||
|
@ -288,6 +288,12 @@ TraceOneDataRelocation(JSTracer *trc, Instruction *inst)
|
||||
void *ptr = (void *)Assembler::ExtractLuiOriValue(inst, inst->next());
|
||||
void *prior = ptr;
|
||||
|
||||
// The low bit shouldn't be set. If it is, we probably got a dummy
|
||||
// pointer inserted by CodeGenerator::visitNurseryObject, but we
|
||||
// shouldn't be able to trigger GC before those are patched to their
|
||||
// real values.
|
||||
MOZ_ASSERT(!(uintptr_t(ptr) & 0x1));
|
||||
|
||||
// No barrier needed since these are constants.
|
||||
gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
|
||||
if (ptr != prior) {
|
||||
@ -322,6 +328,43 @@ Assembler::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReade
|
||||
::TraceDataRelocations(trc, code->raw(), reader);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
|
||||
const ObjectVector &nurseryObjects)
|
||||
{
|
||||
MOZ_ASSERT(!nurseryObjects.empty());
|
||||
|
||||
uint8_t *buffer = code->raw();
|
||||
bool hasNurseryPointers = false;
|
||||
|
||||
while (reader.more()) {
|
||||
size_t offset = reader.readUnsigned();
|
||||
Instruction *inst = (Instruction*)(buffer + offset);
|
||||
|
||||
void *ptr = (void *)Assembler::ExtractLuiOriValue(inst, inst->next());
|
||||
uintptr_t word = uintptr_t(ptr);
|
||||
|
||||
if (!(word & 0x1))
|
||||
continue;
|
||||
|
||||
uint32_t index = word >> 1;
|
||||
JSObject *obj = nurseryObjects[index];
|
||||
|
||||
Assembler::UpdateLuiOriValue(inst, inst->next(), uint32_t(obj));
|
||||
AutoFlushICache::flush(uintptr_t(inst), 8);
|
||||
|
||||
// Either all objects are still in the nursery, or all objects are
|
||||
// tenured.
|
||||
MOZ_ASSERT_IF(hasNurseryPointers, IsInsideNursery(obj));
|
||||
|
||||
if (!hasNurseryPointers && IsInsideNursery(obj))
|
||||
hasNurseryPointers = true;
|
||||
}
|
||||
|
||||
if (hasNurseryPointers)
|
||||
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(code);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::copyJumpRelocationTable(uint8_t *dest)
|
||||
{
|
||||
|
@ -1012,6 +1012,9 @@ class Assembler : public AssemblerShared
|
||||
static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
|
||||
static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
|
||||
|
||||
static void FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
|
||||
const ObjectVector &nurseryObjects);
|
||||
|
||||
static bool SupportsFloatingPoint() {
|
||||
#if (defined(__mips_hard_float) && !defined(__mips_single_float)) || defined(JS_MIPS_SIMULATOR)
|
||||
return true;
|
||||
|
@ -156,6 +156,12 @@ class MacroAssemblerNone : public Assembler
|
||||
static void TraceJumpRelocations(JSTracer *, JitCode *, CompactBufferReader &) { MOZ_CRASH(); }
|
||||
static void TraceDataRelocations(JSTracer *, JitCode *, CompactBufferReader &) { MOZ_CRASH(); }
|
||||
|
||||
static void FixupNurseryObjects(JSContext *, JitCode *, CompactBufferReader &,
|
||||
const ObjectVector &)
|
||||
{
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
static bool SupportsFloatingPoint() { return false; }
|
||||
static bool SupportsSimd() { return false; }
|
||||
|
||||
|
@ -233,6 +233,22 @@ class ImmMaybeNurseryPtr
|
||||
}
|
||||
};
|
||||
|
||||
// Dummy value used for nursery pointers during Ion compilation, see
|
||||
// LNurseryObject.
|
||||
class IonNurseryPtr
|
||||
{
|
||||
const gc::Cell *ptr;
|
||||
|
||||
public:
|
||||
friend class ImmGCPtr;
|
||||
|
||||
explicit IonNurseryPtr(const gc::Cell *ptr) : ptr(ptr)
|
||||
{
|
||||
MOZ_ASSERT(ptr);
|
||||
MOZ_ASSERT(uintptr_t(ptr) & 0x1);
|
||||
}
|
||||
};
|
||||
|
||||
// Used for immediates which require relocation.
|
||||
class ImmGCPtr
|
||||
{
|
||||
@ -248,6 +264,15 @@ class ImmGCPtr
|
||||
MOZ_ASSERT(!IsCompilingAsmJS());
|
||||
}
|
||||
|
||||
explicit ImmGCPtr(IonNurseryPtr ptr) : value(ptr.ptr)
|
||||
{
|
||||
MOZ_ASSERT(!IsPoisonedPtr(value));
|
||||
MOZ_ASSERT(value);
|
||||
|
||||
// asm.js shouldn't be creating GC things
|
||||
MOZ_ASSERT(!IsCompilingAsmJS());
|
||||
}
|
||||
|
||||
private:
|
||||
ImmGCPtr() : value(0) {}
|
||||
|
||||
|
@ -67,6 +67,12 @@ TraceDataRelocations(JSTracer *trc, uint8_t *buffer, CompactBufferReader &reader
|
||||
}
|
||||
#endif
|
||||
|
||||
// The low bit shouldn't be set. If it is, we probably got a dummy
|
||||
// pointer inserted by CodeGenerator::visitNurseryObject, but we
|
||||
// shouldn't be able to trigger GC before those are patched to their
|
||||
// real values.
|
||||
MOZ_ASSERT(!(*reinterpret_cast<uintptr_t *>(ptr) & 0x1));
|
||||
|
||||
// No barrier needed since these are constants.
|
||||
gc::MarkGCThingUnbarriered(trc, ptr, "ion-masm-ptr");
|
||||
}
|
||||
@ -79,6 +85,45 @@ AssemblerX86Shared::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBu
|
||||
::TraceDataRelocations(trc, code->raw(), reader);
|
||||
}
|
||||
|
||||
void
|
||||
AssemblerX86Shared::FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
|
||||
const ObjectVector &nurseryObjects)
|
||||
{
|
||||
MOZ_ASSERT(!nurseryObjects.empty());
|
||||
|
||||
uint8_t *buffer = code->raw();
|
||||
bool hasNurseryPointers = false;
|
||||
|
||||
while (reader.more()) {
|
||||
size_t offset = reader.readUnsigned();
|
||||
void **ptr = X86Encoding::GetPointerRef(buffer + offset);
|
||||
|
||||
uintptr_t *word = reinterpret_cast<uintptr_t *>(ptr);
|
||||
|
||||
#ifdef JS_PUNBOX64
|
||||
if (*word >> JSVAL_TAG_SHIFT)
|
||||
continue; // This is a Value.
|
||||
#endif
|
||||
|
||||
if (!(*word & 0x1))
|
||||
continue;
|
||||
|
||||
uint32_t index = *word >> 1;
|
||||
JSObject *obj = nurseryObjects[index];
|
||||
*word = uintptr_t(obj);
|
||||
|
||||
// Either all objects are still in the nursery, or all objects are
|
||||
// tenured.
|
||||
MOZ_ASSERT_IF(hasNurseryPointers, IsInsideNursery(obj));
|
||||
|
||||
if (!hasNurseryPointers && IsInsideNursery(obj))
|
||||
hasNurseryPointers = true;
|
||||
}
|
||||
|
||||
if (hasNurseryPointers)
|
||||
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(code);
|
||||
}
|
||||
|
||||
void
|
||||
AssemblerX86Shared::trace(JSTracer *trc)
|
||||
{
|
||||
|
@ -327,6 +327,9 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
|
||||
static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
|
||||
|
||||
static void FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader &reader,
|
||||
const ObjectVector &nurseryObjects);
|
||||
|
||||
// MacroAssemblers hold onto gcthings, so they are traced by the GC.
|
||||
void trace(JSTracer *trc);
|
||||
|
||||
|
@ -46,7 +46,7 @@ BEGIN_TEST(testAddPropertyHook)
|
||||
|
||||
JS::RootedObject arrObj(cx, &arr.toObject());
|
||||
for (int i = 0; i < ExpectedCount; ++i) {
|
||||
obj = JS_NewObject(cx, &AddPropertyClass, JS::NullPtr(), JS::NullPtr());
|
||||
obj = JS_NewObject(cx, &AddPropertyClass);
|
||||
CHECK(obj);
|
||||
CHECK(JS_DefineElement(cx, arrObj, i, obj,
|
||||
JSPROP_ENUMERATE,
|
||||
|
@ -40,7 +40,7 @@ BEGIN_TEST(test_CallNonGenericMethodOnProxy)
|
||||
JS::RootedObject globalA(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
|
||||
CHECK(globalA);
|
||||
|
||||
JS::RootedObject customA(cx, JS_NewObject(cx, &CustomClass, JS::NullPtr(), JS::NullPtr()));
|
||||
JS::RootedObject customA(cx, JS_NewObject(cx, &CustomClass));
|
||||
CHECK(customA);
|
||||
JS_SetReservedSlot(customA, CUSTOM_SLOT, Int32Value(17));
|
||||
|
||||
@ -60,7 +60,7 @@ BEGIN_TEST(test_CallNonGenericMethodOnProxy)
|
||||
|
||||
// ...and enter it.
|
||||
JSAutoCompartment enter(cx, globalB);
|
||||
JS::RootedObject customB(cx, JS_NewObject(cx, &CustomClass, JS::NullPtr(), JS::NullPtr()));
|
||||
JS::RootedObject customB(cx, JS_NewObject(cx, &CustomClass));
|
||||
CHECK(customB);
|
||||
JS_SetReservedSlot(customB, CUSTOM_SLOT, Int32Value(42));
|
||||
|
||||
|
@ -68,7 +68,7 @@ BEGIN_TEST(testGCNurseryFinalizer)
|
||||
|
||||
JS::RootedObject obj(cx);
|
||||
|
||||
obj = JS_NewObject(cx, Jsvalify(&TenuredClass), JS::NullPtr(), JS::NullPtr());
|
||||
obj = JS_NewObject(cx, Jsvalify(&TenuredClass));
|
||||
CHECK(!js::gc::IsInsideNursery(obj));
|
||||
|
||||
// Null finalization list with empty nursery.
|
||||
@ -85,7 +85,7 @@ BEGIN_TEST(testGCNurseryFinalizer)
|
||||
CHECK(ranFinalizer == 0);
|
||||
|
||||
// Single finalizable nursery thing.
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
|
||||
CHECK(js::gc::IsInsideNursery(obj));
|
||||
obj = nullptr;
|
||||
rt->gc.minorGC(JS::gcreason::EVICT_NURSERY);
|
||||
@ -93,9 +93,9 @@ BEGIN_TEST(testGCNurseryFinalizer)
|
||||
ranFinalizer = 0;
|
||||
|
||||
// Multiple finalizable nursery things.
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
|
||||
CHECK(js::gc::IsInsideNursery(obj));
|
||||
obj = nullptr;
|
||||
rt->gc.minorGC(JS::gcreason::EVICT_NURSERY);
|
||||
@ -104,13 +104,13 @@ BEGIN_TEST(testGCNurseryFinalizer)
|
||||
|
||||
// Interleaved finalizable things in nursery.
|
||||
obj = JS_NewPlainObject(cx);
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
|
||||
obj = JS_NewPlainObject(cx);
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
|
||||
obj = JS_NewPlainObject(cx);
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
|
||||
obj = JS_NewPlainObject(cx);
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass), JS::NullPtr(), JS::NullPtr());
|
||||
obj = JS_NewObject(cx, Jsvalify(&NurseryClass));
|
||||
obj = JS_NewPlainObject(cx);
|
||||
CHECK(js::gc::IsInsideNursery(obj));
|
||||
obj = nullptr;
|
||||
|
@ -56,8 +56,7 @@ document_resolve(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *res
|
||||
if (!flatStr)
|
||||
return false;
|
||||
if (JS_FlatStringEqualsAscii(flatStr, "all")) {
|
||||
JS::Rooted<JSObject*> docAll(cx,
|
||||
JS_NewObject(cx, &DocumentAllClass, JS::NullPtr(), JS::NullPtr()));
|
||||
JS::Rooted<JSObject*> docAll(cx, JS_NewObject(cx, &DocumentAllClass));
|
||||
if (!docAll)
|
||||
return false;
|
||||
|
||||
@ -82,7 +81,7 @@ static const JSClass document_class = {
|
||||
|
||||
BEGIN_TEST(testLookup_bug570195)
|
||||
{
|
||||
JS::RootedObject obj(cx, JS_NewObject(cx, &document_class, JS::NullPtr(), JS::NullPtr()));
|
||||
JS::RootedObject obj(cx, JS_NewObject(cx, &document_class));
|
||||
CHECK(obj);
|
||||
CHECK(JS_DefineProperty(cx, global, "document", obj, 0));
|
||||
JS::RootedValue v(cx);
|
||||
|
@ -100,7 +100,7 @@ BEGIN_TEST(testNewObject_1)
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, constructHook
|
||||
};
|
||||
JS::RootedObject ctor(cx, JS_NewObject(cx, &cls, JS::NullPtr(), JS::NullPtr()));
|
||||
JS::RootedObject ctor(cx, JS_NewObject(cx, &cls));
|
||||
CHECK(ctor);
|
||||
JS::RootedValue rt2(cx, OBJECT_TO_JSVAL(ctor));
|
||||
obj = JS_New(cx, ctor, JS::HandleValueArray::subarray(argv, 0, 3));
|
||||
|
@ -33,7 +33,7 @@ createMyObject(JSContext* context, unsigned argc, jsval *vp)
|
||||
|
||||
//JS_GC(context); //<- if we make GC here, all is ok
|
||||
|
||||
JSObject* myObject = JS_NewObject(context, &myClass, JS::NullPtr(), JS::NullPtr());
|
||||
JSObject* myObject = JS_NewObject(context, &myClass);
|
||||
*vp = OBJECT_TO_JSVAL(myObject);
|
||||
|
||||
JS_EndRequest(context);
|
||||
|
@ -55,7 +55,7 @@ struct Kennel {
|
||||
MOZ_NEVER_INLINE static Kennel *
|
||||
Allocate(JSContext *cx)
|
||||
{
|
||||
RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_, JS::NullPtr(), JS::NullPtr()));
|
||||
RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_));
|
||||
if (!barker)
|
||||
return nullptr;
|
||||
|
||||
@ -196,7 +196,7 @@ BEGIN_TEST(test_GlobalPersistentRooted)
|
||||
CHECK(!gGlobalRoot.initialized());
|
||||
|
||||
{
|
||||
RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_, JS::NullPtr(), JS::NullPtr()));
|
||||
RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_));
|
||||
CHECK(barker);
|
||||
|
||||
gGlobalRoot.init(cx, barker);
|
||||
|
@ -25,9 +25,9 @@ BEGIN_TEST(testResolveRecursion)
|
||||
my_resolve
|
||||
};
|
||||
|
||||
obj1.init(cx, JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr()));
|
||||
obj1.init(cx, JS_NewObject(cx, &my_resolve_class));
|
||||
CHECK(obj1);
|
||||
obj2.init(cx, JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr()));
|
||||
obj2.init(cx, JS_NewObject(cx, &my_resolve_class));
|
||||
CHECK(obj2);
|
||||
JS_SetPrivate(obj1, this);
|
||||
JS_SetPrivate(obj2, this);
|
||||
|
@ -164,11 +164,7 @@ JSObject *newKey()
|
||||
JS_NULL_OBJECT_OPS
|
||||
};
|
||||
|
||||
JS::RootedObject key(cx);
|
||||
key = JS_NewObject(cx,
|
||||
Jsvalify(&keyClass),
|
||||
JS::NullPtr(),
|
||||
JS::NullPtr());
|
||||
JS::RootedObject key(cx, JS_NewObject(cx, Jsvalify(&keyClass)));
|
||||
if (!key)
|
||||
return nullptr;
|
||||
|
||||
|
@ -2032,12 +2032,12 @@ JS_FireOnNewGlobalObject(JSContext *cx, JS::HandleObject global)
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_NewObject(JSContext *cx, const JSClass *jsclasp, HandleObject proto, HandleObject parent)
|
||||
JS_NewObject(JSContext *cx, const JSClass *jsclasp, HandleObject parent)
|
||||
{
|
||||
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, proto, parent);
|
||||
assertSameCompartment(cx, parent);
|
||||
|
||||
const Class *clasp = Valueify(jsclasp);
|
||||
if (!clasp)
|
||||
@ -2046,7 +2046,7 @@ JS_NewObject(JSContext *cx, const JSClass *jsclasp, HandleObject proto, HandleOb
|
||||
MOZ_ASSERT(clasp != &JSFunction::class_);
|
||||
MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
|
||||
|
||||
JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, parent);
|
||||
JSObject *obj = NewObjectWithClassProto(cx, clasp, nullptr, parent);
|
||||
MOZ_ASSERT_IF(obj, obj->getParent());
|
||||
return obj;
|
||||
}
|
||||
@ -2066,10 +2066,7 @@ JS_NewObjectWithGivenProto(JSContext *cx, const JSClass *jsclasp, HandleObject p
|
||||
MOZ_ASSERT(clasp != &JSFunction::class_);
|
||||
MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
|
||||
|
||||
JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
|
||||
if (obj)
|
||||
MarkTypeObjectUnknownProperties(cx, obj->type());
|
||||
return obj;
|
||||
return NewObjectWithGivenProto(cx, clasp, proto, parent);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
|
@ -2569,8 +2569,7 @@ extern JS_PUBLIC_API(void)
|
||||
JS_FireOnNewGlobalObject(JSContext *cx, JS::HandleObject global);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_NewObject(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> proto,
|
||||
JS::Handle<JSObject*> parent);
|
||||
JS_NewObject(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> parent = JS::NullPtr());
|
||||
|
||||
/* Queries the [[Extensible]] property of the object. */
|
||||
extern JS_PUBLIC_API(bool)
|
||||
@ -2583,8 +2582,8 @@ extern JS_PUBLIC_API(JSRuntime *)
|
||||
JS_GetObjectRuntime(JSObject *obj);
|
||||
|
||||
/*
|
||||
* Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default
|
||||
* proto if proto's actual parameter value is null.
|
||||
* Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default proto.
|
||||
* If proto is JS::NullPtr, the JS object will have `null` as [[Prototype]].
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_NewObjectWithGivenProto(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> proto,
|
||||
|
@ -1074,6 +1074,12 @@ TypeObjectKey::proto()
|
||||
return isTypeObject() ? asTypeObject()->proto() : asSingleObject()->getTaggedProto();
|
||||
}
|
||||
|
||||
TaggedProto
|
||||
TypeObjectKey::protoMaybeInNursery()
|
||||
{
|
||||
return isTypeObject() ? asTypeObject()->proto() : asSingleObject()->getTaggedProto();
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::hasTenuredProto() const
|
||||
{
|
||||
|
@ -1521,10 +1521,8 @@ struct TypeObjectKey
|
||||
static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
|
||||
static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
|
||||
|
||||
static TypeObjectKey *get(JSObject *obj) {
|
||||
MOZ_ASSERT(obj);
|
||||
return (TypeObjectKey *) (uintptr_t(obj) | 1);
|
||||
}
|
||||
static inline TypeObjectKey *get(JSObject *obj);
|
||||
|
||||
static TypeObjectKey *get(TypeObject *obj) {
|
||||
MOZ_ASSERT(obj);
|
||||
return (TypeObjectKey *) obj;
|
||||
@ -1545,6 +1543,7 @@ struct TypeObjectKey
|
||||
|
||||
const Class *clasp();
|
||||
TaggedProto proto();
|
||||
TaggedProto protoMaybeInNursery();
|
||||
bool hasTenuredProto();
|
||||
JSObject *singleton();
|
||||
TypeNewScript *newScript();
|
||||
|
@ -122,6 +122,14 @@ TypeObjectKey::asSingleObject()
|
||||
return res;
|
||||
}
|
||||
|
||||
/* static */ inline TypeObjectKey *
|
||||
TypeObjectKey::get(JSObject *obj)
|
||||
{
|
||||
if (obj->hasSingletonType())
|
||||
return (TypeObjectKey *) (uintptr_t(obj) | 1);
|
||||
return TypeObjectKey::get(obj->type());
|
||||
}
|
||||
|
||||
/* static */ inline Type
|
||||
Type::ObjectType(JSObject *obj)
|
||||
{
|
||||
|
112
js/src/jsobj.cpp
112
js/src/jsobj.cpp
@ -3047,79 +3047,73 @@ js::HasOwnProperty(JSContext *cx, HandleObject obj, HandleId id, bool *result)
|
||||
return true;
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
LookupPropertyPureInline(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
|
||||
Shape **propp)
|
||||
bool
|
||||
js::LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
||||
Shape **propp)
|
||||
{
|
||||
if (!obj->isNative())
|
||||
return false;
|
||||
do {
|
||||
if (obj->isNative()) {
|
||||
/* Search for a native dense element, typed array element, or property. */
|
||||
|
||||
NativeObject *current = &obj->as<NativeObject>();
|
||||
while (true) {
|
||||
/* Search for a native dense element, typed array element, or property. */
|
||||
if (JSID_IS_INT(id) && obj->as<NativeObject>().containsDenseElement(JSID_TO_INT(id))) {
|
||||
*objp = obj;
|
||||
MarkDenseOrTypedArrayElementFound<NoGC>(propp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (JSID_IS_INT(id) && current->containsDenseElement(JSID_TO_INT(id))) {
|
||||
*objp = current;
|
||||
MarkDenseOrTypedArrayElementFound<NoGC>(propp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsAnyTypedArray(current)) {
|
||||
uint64_t index;
|
||||
if (IsTypedArrayIndex(id, &index)) {
|
||||
if (index < AnyTypedArrayLength(obj)) {
|
||||
*objp = current;
|
||||
MarkDenseOrTypedArrayElementFound<NoGC>(propp);
|
||||
} else {
|
||||
*objp = nullptr;
|
||||
*propp = nullptr;
|
||||
if (IsAnyTypedArray(obj)) {
|
||||
uint64_t index;
|
||||
if (IsTypedArrayIndex(id, &index)) {
|
||||
if (index < AnyTypedArrayLength(obj)) {
|
||||
*objp = obj;
|
||||
MarkDenseOrTypedArrayElementFound<NoGC>(propp);
|
||||
} else {
|
||||
*objp = nullptr;
|
||||
*propp = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Shape *shape = obj->as<NativeObject>().lookupPure(id)) {
|
||||
*objp = obj;
|
||||
*propp = shape;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fail if there's a resolve hook. We allow the JSFunction resolve hook
|
||||
// if we know it will never add a property with this name or str_resolve
|
||||
// with a non-integer property.
|
||||
do {
|
||||
const Class *clasp = obj->getClass();
|
||||
if (!clasp->resolve)
|
||||
break;
|
||||
if (clasp->resolve == fun_resolve && !FunctionHasResolveHook(cx->names(), id))
|
||||
break;
|
||||
if (clasp->resolve == str_resolve && !JSID_IS_INT(id))
|
||||
break;
|
||||
return false;
|
||||
} while (0);
|
||||
} else {
|
||||
// Search for a property on an unboxed object. Other non-native objects
|
||||
// are not handled here.
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return false;
|
||||
if (obj->as<UnboxedPlainObject>().layout().lookup(id)) {
|
||||
*objp = obj;
|
||||
MarkNonNativePropertyFound<NoGC>(propp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Shape *shape = current->lookupPure(id)) {
|
||||
*objp = current;
|
||||
*propp = shape;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fail if there's a resolve hook. We allow the JSFunction resolve hook
|
||||
// if we know it will never add a property with this name or str_resolve
|
||||
// with a non-integer property.
|
||||
do {
|
||||
const Class *clasp = current->getClass();
|
||||
if (!clasp->resolve)
|
||||
break;
|
||||
if (clasp->resolve == fun_resolve && !FunctionHasResolveHook(cx->names(), id))
|
||||
break;
|
||||
if (clasp->resolve == str_resolve && !JSID_IS_INT(id))
|
||||
break;
|
||||
return false;
|
||||
} while (0);
|
||||
|
||||
JSObject *proto = current->getProto();
|
||||
|
||||
if (!proto)
|
||||
break;
|
||||
if (!proto->isNative())
|
||||
return false;
|
||||
|
||||
current = &proto->as<NativeObject>();
|
||||
}
|
||||
obj = obj->getProto();
|
||||
} while (obj);
|
||||
|
||||
*objp = nullptr;
|
||||
*propp = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
|
||||
Shape **propp)
|
||||
{
|
||||
return LookupPropertyPureInline(cx, obj, id, objp, propp);
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::reportReadOnly(JSContext *cx, jsid id, unsigned report)
|
||||
{
|
||||
|
@ -1226,7 +1226,7 @@ js_FindVariableScope(JSContext *cx, JSFunction **funp);
|
||||
namespace js {
|
||||
|
||||
bool
|
||||
LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
|
||||
LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
||||
Shape **propp);
|
||||
|
||||
bool
|
||||
|
@ -559,7 +559,7 @@ js::proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
return false;
|
||||
|
||||
if (found) {
|
||||
MarkNonNativePropertyFound(propp);
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
objp.set(obj);
|
||||
} else {
|
||||
objp.set(nullptr);
|
||||
|
@ -1035,7 +1035,7 @@ CacheEntry(JSContext* cx, unsigned argc, JS::Value *vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject obj(cx, JS_NewObject(cx, &CacheEntry_class, JS::NullPtr(), JS::NullPtr()));
|
||||
RootedObject obj(cx, JS_NewObject(cx, &CacheEntry_class));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
@ -4039,7 +4039,7 @@ ObjectEmulatingUndefined(JSContext *cx, unsigned argc, jsval *vp)
|
||||
JSCLASS_EMULATES_UNDEFINED
|
||||
};
|
||||
|
||||
RootedObject obj(cx, JS_NewObject(cx, &cls, JS::NullPtr(), JS::NullPtr()));
|
||||
RootedObject obj(cx, JS_NewObject(cx, &cls));
|
||||
if (!obj)
|
||||
return false;
|
||||
args.rval().setObject(*obj);
|
||||
@ -5092,7 +5092,7 @@ dom_constructor(JSContext* cx, unsigned argc, JS::Value *vp)
|
||||
}
|
||||
|
||||
RootedObject proto(cx, &protov.toObject());
|
||||
RootedObject domObj(cx, JS_NewObject(cx, &dom_class, proto, JS::NullPtr()));
|
||||
RootedObject domObj(cx, JS_NewObjectWithGivenProto(cx, &dom_class, proto, JS::NullPtr()));
|
||||
if (!domObj)
|
||||
return false;
|
||||
|
||||
|
@ -332,6 +332,7 @@ NativeObject::setLastProperty(ExclusiveContext *cx, HandleNativeObject obj, Hand
|
||||
MOZ_ASSERT(!shape->inDictionary());
|
||||
MOZ_ASSERT(shape->compartment() == obj->compartment());
|
||||
MOZ_ASSERT(shape->numFixedSlots() == obj->numFixedSlots());
|
||||
MOZ_ASSERT(shape->getObjectClass() == obj->getClass());
|
||||
|
||||
size_t oldSpan = obj->lastProperty()->slotSpan();
|
||||
size_t newSpan = shape->slotSpan();
|
||||
@ -355,6 +356,7 @@ NativeObject::setLastPropertyShrinkFixedSlots(Shape *shape)
|
||||
MOZ_ASSERT(!shape->inDictionary());
|
||||
MOZ_ASSERT(shape->compartment() == compartment());
|
||||
MOZ_ASSERT(lastProperty()->slotSpan() == shape->slotSpan());
|
||||
MOZ_ASSERT(shape->getObjectClass() == getClass());
|
||||
|
||||
DebugOnly<size_t> oldFixed = numFixedSlots();
|
||||
DebugOnly<size_t> newFixed = shape->numFixedSlots();
|
||||
@ -381,6 +383,30 @@ NativeObject::setLastPropertyMakeNonNative(Shape *shape)
|
||||
shape_ = shape;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
NativeObject::setLastPropertyMakeNative(ExclusiveContext *cx, HandleNativeObject obj,
|
||||
HandleShape shape)
|
||||
{
|
||||
MOZ_ASSERT(obj->getClass()->isNative());
|
||||
MOZ_ASSERT(!obj->lastProperty()->isNative());
|
||||
MOZ_ASSERT(shape->isNative());
|
||||
MOZ_ASSERT(!obj->inDictionaryMode());
|
||||
MOZ_ASSERT(!shape->inDictionary());
|
||||
MOZ_ASSERT(shape->compartment() == obj->compartment());
|
||||
|
||||
obj->shape_ = shape;
|
||||
obj->slots_ = nullptr;
|
||||
obj->elements_ = emptyObjectElements;
|
||||
|
||||
size_t oldSpan = shape->numFixedSlots();
|
||||
size_t newSpan = shape->slotSpan();
|
||||
|
||||
// A failures at this point will leave the object as a mutant, and we
|
||||
// can't recover.
|
||||
if (oldSpan != newSpan && !updateSlotsForSpan(cx, obj, oldSpan, newSpan))
|
||||
CrashAtUnhandlableOOM("NativeObject::setLastPropertyMakeNative");
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
NativeObject::setSlotSpan(ExclusiveContext *cx, HandleNativeObject obj, uint32_t span)
|
||||
{
|
||||
|
@ -417,6 +417,12 @@ class NativeObject : public JSObject
|
||||
// that are (temporarily) inconsistent.
|
||||
void setLastPropertyMakeNonNative(Shape *shape);
|
||||
|
||||
// As for setLastProperty(), but changes the class associated with the
|
||||
// object to a native one. The object's type has already been changed, and
|
||||
// this brings the shape into sync with it.
|
||||
static void setLastPropertyMakeNative(ExclusiveContext *cx, HandleNativeObject obj,
|
||||
HandleShape shape);
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG
|
||||
void checkShapeConsistency();
|
||||
|
@ -1495,8 +1495,9 @@ template<> struct RootKind<BaseShape *> : SpecificRootKind<BaseShape *, THING_RO
|
||||
// properties of non-native objects, and dense elements for native objects.
|
||||
// Use separate APIs for these two cases.
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static inline void
|
||||
MarkNonNativePropertyFound(MutableHandleShape propp)
|
||||
MarkNonNativePropertyFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
|
||||
{
|
||||
propp.set(reinterpret_cast<Shape*>(1));
|
||||
}
|
||||
|
@ -196,15 +196,11 @@ UnboxedPlainObject::convertToNative(JSContext *cx)
|
||||
if (!SetClassAndProto(cx, obj, &PlainObject::class_, proto))
|
||||
return false;
|
||||
|
||||
// Any failures after this point will leave the object as a mutant, and we
|
||||
// can't recover.
|
||||
|
||||
RootedPlainObject nobj(cx, &obj->as<PlainObject>());
|
||||
if (!nobj->setLastProperty(cx, nobj, shape))
|
||||
CrashAtUnhandlableOOM("UnboxedPlainObject::convertToNative");
|
||||
RootedNativeObject nobj(cx, &obj->as<PlainObject>());
|
||||
NativeObject::setLastPropertyMakeNative(cx, nobj, shape);
|
||||
|
||||
for (size_t i = 0; i < values.length(); i++)
|
||||
nobj->initSlot(i, values[i]);
|
||||
nobj->initSlotUnchecked(i, values[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -250,7 +246,7 @@ UnboxedPlainObject::obj_lookupGeneric(JSContext *cx, HandleObject obj,
|
||||
MutableHandleShape propp)
|
||||
{
|
||||
if (obj->as<UnboxedPlainObject>().layout().lookup(id)) {
|
||||
MarkNonNativePropertyFound(propp);
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
@ -28,6 +28,12 @@ UnboxedTypeSize(JSValueType type)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
UnboxedTypeNeedsPreBarrier(JSValueType type)
|
||||
{
|
||||
return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
// Class describing the layout of an UnboxedPlainObject.
|
||||
class UnboxedLayout
|
||||
{
|
||||
|
@ -312,29 +312,33 @@ def print_opcode(opcode):
|
||||
print("""<dt>{names}</dt>
|
||||
<dd>
|
||||
<table class="standard-table">
|
||||
<tbody>
|
||||
<tr><th>Value</th><td><code>{values}</code></td></tr>
|
||||
<tr><th>Operands</th><td><code>{operands}</code></td></tr>
|
||||
<tr><th>Length</th><td><code>{length}</code></td></tr>
|
||||
<tr><th>Stack Uses</th><td><code>{stack_uses}</code></td></tr>
|
||||
<tr><th>Stack Defs</th><td><code>{stack_defs}</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{desc}
|
||||
</dd>
|
||||
""".format(names='<br>'.join(names),
|
||||
values='<br>'.join(values),
|
||||
operands=escape(opcode.operands),
|
||||
operands=escape(opcode.operands) or " ",
|
||||
length=escape(override(opcode.length,
|
||||
opcode.length_override)),
|
||||
stack_uses=escape(opcode.stack_uses),
|
||||
stack_defs=escape(opcode.stack_defs),
|
||||
stack_uses=escape(opcode.stack_uses) or " ",
|
||||
stack_defs=escape(opcode.stack_defs) or " ",
|
||||
desc=opcode.desc)) # desc is already escaped
|
||||
|
||||
def make_element_id(name):
|
||||
return name.replace(' ', '-')
|
||||
|
||||
def print_doc(version, index):
|
||||
print("""<h2 id="Bytecode_Listing">Bytecode Listing</h2>
|
||||
print("""<div>{{{{SpiderMonkeySidebar("Internals")}}}}</div>
|
||||
|
||||
<h2 id="Bytecode_Listing">Bytecode Listing</h2>
|
||||
|
||||
<p>This document is automatically generated from
|
||||
<a href="{source_base}/js/src/vm/Opcodes.h">Opcodes.h</a> and
|
||||
|
@ -588,7 +588,7 @@ mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
|
||||
if (aReuseLoaderGlobal) {
|
||||
// If we're reusing the loader global, we don't actually use the
|
||||
// global, but rather we use a different object as the 'this' object.
|
||||
obj = JS_NewObject(aCx, &kFakeBackstagePassJSClass, NullPtr(), NullPtr());
|
||||
obj = JS_NewObject(aCx, &kFakeBackstagePassJSClass);
|
||||
NS_ENSURE_TRUE(obj, nullptr);
|
||||
}
|
||||
|
||||
|
@ -464,7 +464,7 @@ CreateObjectIn(JSContext *cx, HandleValue vobj, CreateObjectInOptions &options,
|
||||
RootedObject obj(cx);
|
||||
{
|
||||
JSAutoCompartment ac(cx, scope);
|
||||
obj = JS_NewObject(cx, nullptr, JS::NullPtr(), scope);
|
||||
obj = JS_NewObject(cx, nullptr, scope);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
@ -1467,7 +1467,7 @@ JSObject*
|
||||
xpc::NewOutObject(JSContext* cx, JSObject* scope)
|
||||
{
|
||||
RootedObject global(cx, JS_GetGlobalForObject(cx, scope));
|
||||
return JS_NewObject(cx, nullptr, NullPtr(), global);
|
||||
return JS_NewObject(cx, nullptr, global);
|
||||
}
|
||||
|
||||
|
||||
|
@ -808,7 +808,7 @@ XPCWrappedNative::Init(HandleObject parent,
|
||||
return false;
|
||||
}
|
||||
|
||||
mFlatJSObject = JS_NewObject(cx, jsclazz, protoJSObject, parent);
|
||||
mFlatJSObject = JS_NewObjectWithGivenProto(cx, jsclazz, protoJSObject, parent);
|
||||
if (!mFlatJSObject) {
|
||||
mFlatJSObject.unsetFlags(FLAT_JS_OBJECT_VALID);
|
||||
return false;
|
||||
@ -1573,9 +1573,7 @@ XPCWrappedNative::InitTearOffJSObject(XPCWrappedNativeTearOff* to)
|
||||
AutoJSContext cx;
|
||||
|
||||
RootedObject parent(cx, mFlatJSObject);
|
||||
RootedObject proto(cx, JS_GetObjectPrototype(cx, parent));
|
||||
JSObject* obj = JS_NewObject(cx, Jsvalify(&XPC_WN_Tearoff_JSClass),
|
||||
proto, parent);
|
||||
JSObject* obj = JS_NewObject(cx, Jsvalify(&XPC_WN_Tearoff_JSClass), parent);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<html><head>
|
||||
<html class="reftest-wait"><head>
|
||||
<style>
|
||||
*::first-line { font-size:310%; }
|
||||
</style>
|
||||
@ -104,10 +104,13 @@ mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmm
|
||||
mmmmmmmmmmmmmmmmmmmmmmmmmm
|
||||
</span>
|
||||
<script>
|
||||
function finish() {
|
||||
document.documentElement.removeAttribute('class');
|
||||
}
|
||||
function doe(){
|
||||
document.body.removeAttribute('style');
|
||||
document.body.removeAttribute('style');
|
||||
setTimeout(finish, 100);
|
||||
}
|
||||
setTimeout(doe,300,0);
|
||||
setTimeout(function() {window.location.reload()}, 600);
|
||||
</script>
|
||||
</body></html>
|
||||
</body></html>
|
||||
|
@ -125,7 +125,7 @@ load 385344-2.html
|
||||
load 385414-1.html
|
||||
load 385414-2.html
|
||||
load 385426-1.html
|
||||
skip-if(B2G) skip-if(Android&&AndroidVersion==10) load 385526.html # Bug 891347
|
||||
load 385526.html
|
||||
load 385681.html
|
||||
load 385885-1.xul
|
||||
load 386799-1.html
|
||||
|
@ -226,6 +226,15 @@ nsFirstLetterFrame::Reflow(nsPresContext* aPresContext,
|
||||
aMetrics.SetSize(wm, convertedSize);
|
||||
aMetrics.SetBlockStartAscent(kidMetrics.BlockStartAscent() +
|
||||
bp.BStart(wm));
|
||||
|
||||
// Ensure that the overflow rect contains the child textframe's
|
||||
// overflow rect.
|
||||
// Note that if this is floating, the overline/underline drawable
|
||||
// area is in the overflow rect of the child textframe.
|
||||
aMetrics.UnionOverflowAreasWithDesiredBounds();
|
||||
ConsiderChildOverflow(aMetrics.mOverflowAreas, kid);
|
||||
|
||||
FinishAndStoreOverflow(&aMetrics);
|
||||
}
|
||||
else {
|
||||
// Pretend we are a span and reflow the child frame
|
||||
@ -247,12 +256,6 @@ nsFirstLetterFrame::Reflow(nsPresContext* aPresContext,
|
||||
nsLayoutUtils::SetBSizeFromFontMetrics(this, aMetrics, bp, lineWM, wm);
|
||||
}
|
||||
|
||||
// Ensure that the overflow rect contains the child textframe's overflow rect.
|
||||
// Note that if this is floating, the overline/underline drawable area is in
|
||||
// the overflow rect of the child textframe.
|
||||
aMetrics.UnionOverflowAreasWithDesiredBounds();
|
||||
ConsiderChildOverflow(aMetrics.mOverflowAreas, kid);
|
||||
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
||||
// Create a continuation or remove existing continuations based on
|
||||
// the reflow completion status.
|
||||
@ -287,8 +290,6 @@ nsFirstLetterFrame::Reflow(nsPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
|
||||
FinishAndStoreOverflow(&aMetrics);
|
||||
|
||||
NS_FRAME_SET_TRUNCATION(aReflowStatus, aReflowState, aMetrics);
|
||||
}
|
||||
|
||||
|
@ -916,7 +916,7 @@ fuzzy-if(Android&&AndroidVersion>=15,8,50) == 404553-1.html 404553-1-ref.html #
|
||||
== 407016-1-b.html 407016-1-ref.html
|
||||
== 407078-1.html 407078-1-ref.html
|
||||
== 407095-1.html 407095-1-ref.html
|
||||
== 407111-1.html 407111-1-ref.html
|
||||
fuzzy-if(Android,13,9) == 407111-1.html 407111-1-ref.html # Bug 1128229
|
||||
== 407227-1.html 407227-1-ref.html
|
||||
== 407243-1.html 407243-1-ref.html
|
||||
== 407419-1.html 407419-1-ref.html
|
||||
|
@ -0,0 +1,14 @@
|
||||
<title>::first-letter and overflow</title>
|
||||
<style>
|
||||
|
||||
div {
|
||||
height: 8em; width: 5em;
|
||||
padding: 3px;
|
||||
background: yellow; color: black;
|
||||
line-height: 1.0;
|
||||
}
|
||||
div::first-letter { font-size: 1.2em; float: left; }
|
||||
|
||||
</style>
|
||||
|
||||
<div>Hello world, testing, testing, testing, testing</div>
|
15
layout/reftests/first-letter/overflow-float-nooverflow.html
Normal file
15
layout/reftests/first-letter/overflow-float-nooverflow.html
Normal file
@ -0,0 +1,15 @@
|
||||
<title>::first-letter and overflow</title>
|
||||
<style>
|
||||
|
||||
div {
|
||||
height: 8em; width: 5em;
|
||||
padding: 3px;
|
||||
background: yellow; color: black;
|
||||
overflow: auto;
|
||||
line-height: 1.0;
|
||||
}
|
||||
div::first-letter { font-size: 1.2em; float: left; }
|
||||
|
||||
</style>
|
||||
|
||||
<div>Hello world, testing, testing, testing, testing</div>
|
@ -0,0 +1,14 @@
|
||||
<title>::first-letter and overflow</title>
|
||||
<style>
|
||||
|
||||
div {
|
||||
height: 3em; width: 8em;
|
||||
padding: 3px;
|
||||
background: yellow; color: black;
|
||||
line-height: 1.0;
|
||||
}
|
||||
div::first-letter { font-size: 4em; float: left; }
|
||||
|
||||
</style>
|
||||
|
||||
<div>Hello</div>
|
15
layout/reftests/first-letter/overflow-float-overflow.html
Normal file
15
layout/reftests/first-letter/overflow-float-overflow.html
Normal file
@ -0,0 +1,15 @@
|
||||
<title>::first-letter and overflow</title>
|
||||
<style>
|
||||
|
||||
div {
|
||||
height: 3em; width: 8em;
|
||||
padding: 3px;
|
||||
background: yellow; color: black;
|
||||
overflow: auto;
|
||||
line-height: 1.0;
|
||||
}
|
||||
div::first-letter { font-size: 4em; float: left; }
|
||||
|
||||
</style>
|
||||
|
||||
<div>Hello</div>
|
@ -0,0 +1,14 @@
|
||||
<title>::first-letter and overflow</title>
|
||||
<style>
|
||||
|
||||
div {
|
||||
height: 8em; width: 5em;
|
||||
padding: 3px;
|
||||
background: yellow; color: black;
|
||||
line-height: 1.0;
|
||||
}
|
||||
div::first-letter { font-size: 1.2em }
|
||||
|
||||
</style>
|
||||
|
||||
<div>Hello world, testing, testing, testing, testing</div>
|
15
layout/reftests/first-letter/overflow-inline-nooverflow.html
Normal file
15
layout/reftests/first-letter/overflow-inline-nooverflow.html
Normal file
@ -0,0 +1,15 @@
|
||||
<title>::first-letter and overflow</title>
|
||||
<style>
|
||||
|
||||
div {
|
||||
height: 8em; width: 5em;
|
||||
padding: 3px;
|
||||
background: yellow; color: black;
|
||||
overflow: auto;
|
||||
line-height: 1.0;
|
||||
}
|
||||
div::first-letter { font-size: 1.2em }
|
||||
|
||||
</style>
|
||||
|
||||
<div>Hello world, testing, testing, testing, testing</div>
|
@ -0,0 +1,14 @@
|
||||
<title>::first-letter and overflow</title>
|
||||
<style>
|
||||
|
||||
div {
|
||||
height: 3em; width: 8em;
|
||||
padding: 3px;
|
||||
background: yellow; color: black;
|
||||
line-height: 1.0;
|
||||
}
|
||||
div::first-letter { font-size: 4em }
|
||||
|
||||
</style>
|
||||
|
||||
<div>Hello</div>
|
@ -0,0 +1,15 @@
|
||||
<title>::first-letter and overflow</title>
|
||||
<style>
|
||||
|
||||
div {
|
||||
height: 3em; width: 8em;
|
||||
padding: 3px;
|
||||
background: yellow; color: black;
|
||||
overflow: auto;
|
||||
line-height: 1.0;
|
||||
}
|
||||
span { font-size: 4em }
|
||||
|
||||
</style>
|
||||
|
||||
<div><span>H</span>ello</div>
|
15
layout/reftests/first-letter/overflow-inline-overflow.html
Normal file
15
layout/reftests/first-letter/overflow-inline-overflow.html
Normal file
@ -0,0 +1,15 @@
|
||||
<title>::first-letter and overflow</title>
|
||||
<style>
|
||||
|
||||
div {
|
||||
height: 3em; width: 8em;
|
||||
padding: 3px;
|
||||
background: yellow; color: black;
|
||||
overflow: auto;
|
||||
line-height: 1.0;
|
||||
}
|
||||
div::first-letter { font-size: 4em }
|
||||
|
||||
</style>
|
||||
|
||||
<div>Hello</div>
|
@ -67,3 +67,8 @@ fails-if(winWidget||cocoaWidget) == 617869-1.html 617869-1-ref.html
|
||||
fails-if(gtk2Widget) random-if(winWidget&&!d2d) == font-text-styles-floater.html font-text-styles-floater-ref.html # bug 992846
|
||||
== inline-height-empty.html inline-height-empty-ref.html
|
||||
HTTP(..) == indic-clusters-1.html indic-clusters-1-ref.html
|
||||
== overflow-float-nooverflow.html overflow-float-nooverflow-ref.html
|
||||
== overflow-float-overflow.html overflow-float-overflow-notref.html
|
||||
== overflow-inline-nooverflow.html overflow-inline-nooverflow-ref.html
|
||||
!= overflow-inline-overflow.html overflow-inline-overflow-notref.html
|
||||
== overflow-inline-overflow.html overflow-inline-overflow-ref.html
|
||||
|
@ -1,6 +1,6 @@
|
||||
skip-if(B2G) == ellipsis-font-fallback.html ellipsis-font-fallback-ref.html
|
||||
== line-clipping.html line-clipping-ref.html
|
||||
skip-if(B2G) HTTP(..) == marker-basic.html marker-basic-ref.html
|
||||
fuzzy-if(Android,16,244) skip-if(B2G) HTTP(..) == marker-basic.html marker-basic-ref.html # Bug 1128229
|
||||
skip-if(B2G) HTTP(..) == marker-string.html marker-string-ref.html
|
||||
skip-if(Android||B2G) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
|
||||
skip-if(!gtk2Widget) fuzzy-if(gtk2Widget,1,104) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user