Merge m-c to b2g-inbound.

This commit is contained in:
Ryan VanderMeulen 2013-11-12 15:36:21 -05:00
commit ea3219930a
106 changed files with 3882 additions and 3206 deletions

View File

@ -42,6 +42,7 @@
#endif
#include "mozilla/Telemetry.h"
#include "mozilla/WindowsDllBlocklist.h"
static void Output(const char *fmt, ... )
{
@ -92,9 +93,6 @@ public:
XRE_GetFileFromPathType XRE_GetFileFromPath;
XRE_CreateAppDataType XRE_CreateAppData;
XRE_FreeAppDataType XRE_FreeAppData;
#ifdef XRE_HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklistType XRE_SetupDllBlocklist;
#endif
XRE_TelemetryAccumulateType XRE_TelemetryAccumulate;
XRE_mainType XRE_main;
@ -102,9 +100,6 @@ static const nsDynamicFunctionLoad kXULFuncs[] = {
{ "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
{ "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
{ "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
#ifdef XRE_HAS_DLL_BLOCKLIST
{ "XRE_SetupDllBlocklist", (NSFuncPtr*) &XRE_SetupDllBlocklist },
#endif
{ "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
{ "XRE_main", (NSFuncPtr*) &XRE_main },
{ nullptr, nullptr }
@ -210,6 +205,10 @@ int main(int argc, char* argv[])
gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
#endif
#ifdef HAS_DLL_BLOCKLIST
DllBlocklist_Initialize();
#endif
// We do this because of data in bug 771745
XPCOMGlueEnablePreload();
@ -227,10 +226,6 @@ int main(int argc, char* argv[])
return 255;
}
#ifdef XRE_HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklist();
#endif
if (gotCounters) {
#if defined(XP_WIN)
XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS,

View File

@ -46,6 +46,7 @@
#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
#include "mozilla/Telemetry.h"
#include "mozilla/WindowsDllBlocklist.h"
using namespace mozilla;
@ -78,9 +79,19 @@ static void Output(const char *fmt, ... )
#if MOZ_WINCONSOLE
fwprintf_s(stderr, wide_msg);
#else
MessageBoxW(nullptr, wide_msg, L"Firefox", MB_OK
| MB_ICONERROR
| MB_SETFOREGROUND);
// Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
// This is a rare codepath, so we can load user32 at run-time instead.
HMODULE user32 = LoadLibraryW(L"user32.dll");
if (user32) {
typedef int (WINAPI * MessageBoxWFn)(HWND, LPCWSTR, LPCWSTR, UINT);
MessageBoxWFn messageBoxW = (MessageBoxWFn)GetProcAddress(user32, "MessageBoxW");
if (messageBoxW) {
messageBoxW(nullptr, wide_msg, L"Firefox", MB_OK
| MB_ICONERROR
| MB_SETFOREGROUND);
}
FreeLibrary(user32);
}
#endif
#endif
@ -144,9 +155,6 @@ static void AttachToTestHarness()
XRE_GetFileFromPathType XRE_GetFileFromPath;
XRE_CreateAppDataType XRE_CreateAppData;
XRE_FreeAppDataType XRE_FreeAppData;
#ifdef XRE_HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklistType XRE_SetupDllBlocklist;
#endif
XRE_TelemetryAccumulateType XRE_TelemetryAccumulate;
XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
XRE_mainType XRE_main;
@ -156,9 +164,6 @@ static const nsDynamicFunctionLoad kXULFuncs[] = {
{ "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
{ "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
{ "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
#ifdef XRE_HAS_DLL_BLOCKLIST
{ "XRE_SetupDllBlocklist", (NSFuncPtr*) &XRE_SetupDllBlocklist },
#endif
{ "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
{ "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord },
{ "XRE_main", (NSFuncPtr*) &XRE_main },
@ -597,6 +602,17 @@ int main(int argc, char* argv[])
nsIFile *xreDirectory;
#ifdef HAS_DLL_BLOCKLIST
DllBlocklist_Initialize();
// In order to be effective against AppInit DLLs, the blocklist must be
// initialized before user32.dll is loaded into the process. If this assert
// ever fires, then the fix for bug 932100 has been defeated and the
// blocklist will miss AppInit DLLs. You should use a delayload or reorder
// the code to prevent user32.dll from loading during early startup.
MOZ_ASSERT(!GetModuleHandleA("user32.dll"));
#endif
nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory);
if (NS_FAILED(rv)) {
return 255;
@ -604,10 +620,6 @@ int main(int argc, char* argv[])
XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
#ifdef XRE_HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklist();
#endif
if (gotCounters) {
#if defined(XP_WIN)
XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS,

View File

@ -800,7 +800,7 @@ else # !WINNT || GNU_CC
endif # WINNT && !GNU_CC
ifdef ENABLE_STRIP
$(STRIP) $@
$(STRIP) $(STRIP_FLAGS) $@
endif
ifdef MOZ_POST_PROGRAM_COMMAND
$(MOZ_POST_PROGRAM_COMMAND) $@
@ -856,7 +856,7 @@ else
endif # WINNT && !GNU_CC
ifdef ENABLE_STRIP
$(STRIP) $@
$(STRIP) $(STRIP_FLAGS) $@
endif
ifdef MOZ_POST_PROGRAM_COMMAND
$(MOZ_POST_PROGRAM_COMMAND) $@
@ -883,7 +883,6 @@ $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(REPORT_BUILD)
$(RM) $(LIBRARY)
$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(SHARED_LIBRARY_LIBS)
$(RANLIB) $@
$(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
# When we only build a library descriptor, blow out any existing library
@ -917,14 +916,12 @@ $(IMPORT_LIBRARY): $(SHARED_LIBRARY)
$(REPORT_BUILD)
$(RM) $@
$(IMPLIB) $@ $^
$(RANLIB) $@
endif # OS/2
$(HOST_LIBRARY): $(HOST_OBJS) Makefile
$(REPORT_BUILD)
$(RM) $@
$(EXPAND_LIBS_EXEC) --extract -- $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
$(HOST_RANLIB) $@
ifdef HAVE_DTRACE
ifndef XP_MACOSX
@ -975,7 +972,7 @@ endif # WINNT && !GCC
@$(RM) foodummyfilefoo $(DELETE_AFTER_LINK)
chmod +x $@
ifdef ENABLE_STRIP
$(STRIP) $@
$(STRIP) $(STRIP_FLAGS) $@
endif
ifdef MOZ_POST_DSO_LIB_COMMAND
$(MOZ_POST_DSO_LIB_COMMAND) $@

View File

@ -306,7 +306,7 @@ dnl to use the cross-compile setup for now
dnl ========================================================
dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269)
AR_FLAGS='cr $@'
AR_FLAGS='crs $@'
if test "$COMPILE_ENVIRONMENT"; then
@ -8872,7 +8872,27 @@ dnl so that regeneration via dependencies works correctly
WEBRTC_CONFIG="${WEBRTC_CONFIG} -D have_ethtool_cmd_speed_hi=0"
fi
GYP_WEBRTC_OPTIONS="--format=mozmake ${WEBRTC_CONFIG} -D target_arch=${WEBRTC_TARGET_ARCH} ${EXTRA_GYP_DEFINES} --depth=${srcdir}/media/webrtc/trunk --toplevel-dir=${srcdir} -G OBJDIR=${_objdir}"
if test -n "$CROSS_COMPILE"; then
case "$target" in
*-mingw*)
GYP_MOZMAKE_OPTIONS="-G os=win"
;;
*-darwin*)
GYP_MOZMAKE_OPTIONS="-G os=mac"
if test "$MACOS_SDK_DIR"; then
GYP_MOZMAKE_OPTIONS="${GYP_MOZMAKE_OPTIONS} -D mac_sdk_path=$MACOS_SDK_DIR"
fi
;;
*-android*)
GYP_MOZMAKE_OPTIONS="-G os=linux"
;;
*)
AC_MSG_ERROR([Don't know what options to give to WebRTC for cross-compilation])
;;
esac
fi
GYP_WEBRTC_OPTIONS="--format=mozmake ${GYP_MOZMAKE_OPTIONS} ${WEBRTC_CONFIG} -D target_arch=${WEBRTC_TARGET_ARCH} ${EXTRA_GYP_DEFINES} --depth=${srcdir}/media/webrtc/trunk --toplevel-dir=${srcdir} -G OBJDIR=${_objdir}"
$PYTHON ${srcdir}/media/webrtc/trunk/build/gyp_chromium \
$GYP_WEBRTC_OPTIONS \

View File

@ -15,12 +15,14 @@
SpecialPowers.pushPrefEnv(
{'set':[["security.csp.speccompliant", true]]},
function() {
SimpleTest.waitForExplicitFinish();
var testframe = document.getElementById('testframe');
testframe.src = 'file_policyuri_regression_from_multipolicy.html';
testframe.addEventListener('load', function checkInlineScriptExecuted () {
is(this.contentDocument.getElementById('testdiv').innerHTML,
'Inline Script Executed',
'Inline script should execute (it would be blocked by the policy, but the policy is report-only)');
SimpleTest.finish();
});
}
);

View File

@ -2716,6 +2716,7 @@ WebGLContext::Uniform1i(WebGLUniformLocation *location_object, GLint a1)
if (!ValidateUniformSetter("Uniform1i", location_object, location))
return;
// Only uniform1i can take sampler settings.
if (!ValidateSamplerUniformSetter("Uniform1i", location_object, a1))
return;
@ -2731,12 +2732,6 @@ WebGLContext::Uniform2i(WebGLUniformLocation *location_object, GLint a1,
if (!ValidateUniformSetter("Uniform2i", location_object, location))
return;
if (!ValidateSamplerUniformSetter("Uniform2i", location_object, a1) ||
!ValidateSamplerUniformSetter("Uniform2i", location_object, a2))
{
return;
}
MakeContextCurrent();
gl->fUniform2i(location, a1, a2);
}
@ -2749,13 +2744,6 @@ WebGLContext::Uniform3i(WebGLUniformLocation *location_object, GLint a1,
if (!ValidateUniformSetter("Uniform3i", location_object, location))
return;
if (!ValidateSamplerUniformSetter("Uniform3i", location_object, a1) ||
!ValidateSamplerUniformSetter("Uniform3i", location_object, a2) ||
!ValidateSamplerUniformSetter("Uniform3i", location_object, a3))
{
return;
}
MakeContextCurrent();
gl->fUniform3i(location, a1, a2, a3);
}
@ -2768,14 +2756,6 @@ WebGLContext::Uniform4i(WebGLUniformLocation *location_object, GLint a1,
if (!ValidateUniformSetter("Uniform4i", location_object, location))
return;
if (!ValidateSamplerUniformSetter("Uniform4i", location_object, a1) ||
!ValidateSamplerUniformSetter("Uniform4i", location_object, a2) ||
!ValidateSamplerUniformSetter("Uniform4i", location_object, a3) ||
!ValidateSamplerUniformSetter("Uniform4i", location_object, a4))
{
return;
}
MakeContextCurrent();
gl->fUniform4i(location, a1, a2, a3, a4);
}

View File

@ -8,8 +8,8 @@
</head>
<script type="application/javascript">
function doTest() {
sendMouseEvent({type:'click'}, 'anchor');
window.parent.postMessage({type: "attempted"}, "*");
sendMouseEvent({type:'click'}, 'anchor');
}
</script>
<body onload="doTest()">

View File

@ -267,8 +267,8 @@ function doIf10TestPart2() {
<iframe sandbox="allow-scripts" id="if_1" src="file_iframe_sandbox_d_if1.html" height="10" width="10"></iframe>
<iframe sandbox="allow-scripts" id="if_2" src="file_iframe_sandbox_d_if2.html" height="10" width="10"></iframe>
<iframe sandbox="allow-scripts" id="if_3" src="file_iframe_sandbox_d_if3.html" height="10" width="10"></iframe>
<iframe id="if_sibling" name="if_sibling" src="about:blank" height="10" width="10"></iframe>
<iframe sandbox="allow-scripts allow-same-origin" id="if_5" src="file_iframe_sandbox_d_if5.html" height="10" width="10"></iframe>
<iframe id="if_sibling" name="if_sibling" src="file_iframe_sandbox_navigation_start.html" height="10" width="10"></iframe>
<iframe sandbox="allow-scripts" id="if_6" src="file_iframe_sandbox_d_if6.html" height="10" width="10"></iframe>
<iframe sandbox="allow-same-origin allow-scripts" id="if_8" src="file_iframe_sandbox_d_if8.html" height="10" width="10"></iframe>
<iframe sandbox="allow-same-origin allow-scripts" id="if_9" src="file_iframe_sandbox_d_if9.html" height="10" width="10"></iframe>

View File

@ -55,7 +55,8 @@ public:
{
}
NS_IMETHOD_(void) DescribeGCedNode(bool aIsMarked,
const char* aObjName)
const char* aObjName,
uint64_t aCompartmentAddress)
{
}

View File

@ -490,13 +490,17 @@ RTCPeerConnection.prototype = {
constraints = {};
}
this._mustValidateConstraints(constraints, "createOffer passed invalid constraints");
this._onCreateOfferSuccess = onSuccess;
this._onCreateOfferFailure = onError;
this._queueOrRun({ func: this._createOffer, args: [constraints], wait: true });
this._queueOrRun({
func: this._createOffer,
args: [onSuccess, onError, constraints],
wait: true
});
},
_createOffer: function(constraints) {
_createOffer: function(onSuccess, onError, constraints) {
this._onCreateOfferSuccess = onSuccess;
this._onCreateOfferFailure = onError;
this._getPC().createOffer(constraints);
},
@ -542,12 +546,6 @@ RTCPeerConnection.prototype = {
},
setLocalDescription: function(desc, onSuccess, onError) {
// TODO -- if we have two setLocalDescriptions in the
// queue,this code overwrites the callbacks for the first
// one with the callbacks for the second one. See Bug 831759.
this._onSetLocalDescriptionSuccess = onSuccess;
this._onSetLocalDescriptionFailure = onError;
let type;
switch (desc.type) {
case "offer":
@ -565,23 +563,19 @@ RTCPeerConnection.prototype = {
this._queueOrRun({
func: this._setLocalDescription,
args: [type, desc.sdp],
args: [type, desc.sdp, onSuccess, onError],
wait: true,
type: desc.type
});
},
_setLocalDescription: function(type, sdp) {
_setLocalDescription: function(type, sdp, onSuccess, onError) {
this._onSetLocalDescriptionSuccess = onSuccess;
this._onSetLocalDescriptionFailure = onError;
this._getPC().setLocalDescription(type, sdp);
},
setRemoteDescription: function(desc, onSuccess, onError) {
// TODO -- if we have two setRemoteDescriptions in the
// queue, this code overwrites the callbacks for the first
// one with the callbacks for the second one. See Bug 831759.
this._onSetRemoteDescriptionSuccess = onSuccess;
this._onSetRemoteDescriptionFailure = onError;
let type;
switch (desc.type) {
case "offer":
@ -599,13 +593,15 @@ RTCPeerConnection.prototype = {
this._queueOrRun({
func: this._setRemoteDescription,
args: [type, desc.sdp],
args: [type, desc.sdp, onSuccess, onError],
wait: true,
type: desc.type
});
},
_setRemoteDescription: function(type, sdp) {
_setRemoteDescription: function(type, sdp, onSuccess, onError) {
this._onSetRemoteDescriptionSuccess = onSuccess;
this._onSetRemoteDescriptionFailure = onError;
this._getPC().setRemoteDescription(type, sdp);
},

View File

@ -6,7 +6,7 @@
MODULE = 'editor'
SOURCES += [
UNIFIED_SOURCES += [
'nsComposerCommands.cpp',
'nsComposerCommandsUpdater.cpp',
'nsComposerController.cpp',

View File

@ -23,10 +23,6 @@
#include "nsAString.h"
#include <algorithm>
#ifdef DEBUG
static bool gNoisy = false;
#endif
using namespace mozilla;
CreateElementTxn::CreateElementTxn()
@ -61,16 +57,6 @@ NS_IMETHODIMP CreateElementTxn::Init(nsEditor *aEditor,
NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
{
#ifdef DEBUG
if (gNoisy)
{
char* nodename = ToNewCString(mTag);
printf("Do Create Element parent = %p <%s>, offset = %d\n",
static_cast<void*>(mParent.get()), nodename, mOffsetInParent);
nsMemory::Free(nodename);
}
#endif
NS_ASSERTION(mEditor && mParent, "bad state");
NS_ENSURE_TRUE(mEditor && mParent, NS_ERROR_NOT_INITIALIZED);
@ -85,13 +71,6 @@ NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
// Try to insert formatting whitespace for the new node:
mEditor->MarkNodeDirty(mNewNode);
#ifdef DEBUG
if (gNoisy)
{
printf(" newNode = %p\n", static_cast<void*>(mNewNode.get()));
}
#endif
// insert the new node
if (CreateElementTxn::eAppend == int32_t(mOffsetInParent)) {
ErrorResult rv;
@ -133,15 +112,6 @@ NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
NS_IMETHODIMP CreateElementTxn::UndoTransaction(void)
{
#ifdef DEBUG
if (gNoisy)
{
printf("Undo Create Element, mParent = %p, node = %p\n",
static_cast<void*>(mParent.get()),
static_cast<void*>(mNewNode.get()));
}
#endif
NS_ASSERTION(mEditor && mParent, "bad state");
NS_ENSURE_TRUE(mEditor && mParent, NS_ERROR_NOT_INITIALIZED);
@ -152,10 +122,6 @@ NS_IMETHODIMP CreateElementTxn::UndoTransaction(void)
NS_IMETHODIMP CreateElementTxn::RedoTransaction(void)
{
#ifdef DEBUG
if (gNoisy) { printf("Redo Create Element\n"); }
#endif
NS_ASSERTION(mEditor && mParent, "bad state");
NS_ENSURE_TRUE(mEditor && mParent, NS_ERROR_NOT_INITIALIZED);

View File

@ -19,11 +19,6 @@
using namespace mozilla;
#ifdef DEBUG
static bool gNoisy = false;
#endif
InsertElementTxn::InsertElementTxn()
: EditTxn()
{
@ -57,23 +52,6 @@ NS_IMETHODIMP InsertElementTxn::Init(nsINode *aNode,
NS_IMETHODIMP InsertElementTxn::DoTransaction(void)
{
#ifdef DEBUG
if (gNoisy)
{
nsCOMPtr<nsIContent>nodeAsContent = do_QueryInterface(mNode);
nsCOMPtr<nsIContent>parentAsContent = do_QueryInterface(mParent);
nsString namestr = mNode->NodeName();
char* nodename = ToNewCString(namestr);
printf("%p Do Insert Element of %p <%s> into parent %p at offset %d\n",
static_cast<void*>(this),
static_cast<void*>(nodeAsContent.get()),
nodename,
static_cast<void*>(parentAsContent.get()),
mOffset);
nsMemory::Free(nodename);
}
#endif
NS_ENSURE_TRUE(mNode && mParent, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsINode> parent = do_QueryInterface(mParent);
@ -115,17 +93,6 @@ NS_IMETHODIMP InsertElementTxn::DoTransaction(void)
NS_IMETHODIMP InsertElementTxn::UndoTransaction(void)
{
#ifdef DEBUG
if (gNoisy)
{
printf("%p Undo Insert Element of %p into parent %p at offset %d\n",
static_cast<void*>(this),
static_cast<void*>(mNode.get()),
static_cast<void*>(mParent.get()),
mOffset);
}
#endif
NS_ENSURE_TRUE(mNode && mParent, NS_ERROR_NOT_INITIALIZED);
ErrorResult rv;

View File

@ -15,10 +15,6 @@
#include "nsISupportsUtils.h" // for NS_ADDREF_THIS, NS_RELEASE
#include "nsITransaction.h" // for nsITransaction
#ifdef DEBUG
static bool gNoisy = false;
#endif
InsertTextTxn::InsertTextTxn()
: EditTxn()
{
@ -62,14 +58,6 @@ NS_IMETHODIMP InsertTextTxn::Init(nsIDOMCharacterData *aElement,
NS_IMETHODIMP InsertTextTxn::DoTransaction(void)
{
#ifdef DEBUG
if (gNoisy)
{
printf("Do Insert Text element = %p\n",
static_cast<void*>(mElement.get()));
}
#endif
NS_ASSERTION(mElement && mEditor, "bad state");
if (!mElement || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
@ -98,14 +86,6 @@ NS_IMETHODIMP InsertTextTxn::DoTransaction(void)
NS_IMETHODIMP InsertTextTxn::UndoTransaction(void)
{
#ifdef DEBUG
if (gNoisy)
{
printf("Undo Insert Text element = %p\n",
static_cast<void*>(mElement.get()));
}
#endif
NS_ASSERTION(mElement && mEditor, "bad state");
if (!mElement || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
@ -133,13 +113,6 @@ NS_IMETHODIMP InsertTextTxn::Merge(nsITransaction *aTransaction, bool *aDidMerge
otherInsTxn->GetData(otherData);
mStringToInsert += otherData;
*aDidMerge = true;
#ifdef DEBUG
if (gNoisy)
{
printf("InsertTextTxn assimilated %p\n",
static_cast<void*>(aTransaction));
}
#endif
}
NS_RELEASE(otherInsTxn);
}

View File

@ -17,10 +17,6 @@
using namespace mozilla;
#ifdef DEBUG
static bool gNoisy = false;
#endif
JoinElementTxn::JoinElementTxn()
: EditTxn()
{
@ -54,16 +50,6 @@ NS_IMETHODIMP JoinElementTxn::Init(nsEditor *aEditor,
// After DoTransaction() and RedoTransaction(), the left node is removed from the content tree and right node remains.
NS_IMETHODIMP JoinElementTxn::DoTransaction(void)
{
#ifdef DEBUG
if (gNoisy)
{
printf("%p Do Join of %p and %p\n",
static_cast<void*>(this),
static_cast<void*>(mLeftNode.get()),
static_cast<void*>(mRightNode.get()));
}
#endif
NS_PRECONDITION((mEditor && mLeftNode && mRightNode), "null arg");
if (!mEditor || !mLeftNode || !mRightNode) { return NS_ERROR_NOT_INITIALIZED; }
@ -85,30 +71,13 @@ NS_IMETHODIMP JoinElementTxn::DoTransaction(void)
mParent = leftParent;
mOffset = mLeftNode->Length();
nsresult rv = mEditor->JoinNodesImpl(mRightNode, mLeftNode, mParent);
#ifdef DEBUG
if (NS_SUCCEEDED(rv) && gNoisy) {
printf(" left node = %p removed\n", static_cast<void*>(mLeftNode.get()));
}
#endif
return rv;
return mEditor->JoinNodesImpl(mRightNode, mLeftNode, mParent);
}
//XXX: what if instead of split, we just deleted the unneeded children of mRight
// and re-inserted mLeft?
NS_IMETHODIMP JoinElementTxn::UndoTransaction(void)
{
#ifdef DEBUG
if (gNoisy)
{
printf("%p Undo Join, right node = %p\n",
static_cast<void*>(this),
static_cast<void*>(mRightNode.get()));
}
#endif
NS_ASSERTION(mRightNode && mLeftNode && mParent, "bad state");
if (!mRightNode || !mLeftNode || !mParent) { return NS_ERROR_NOT_INITIALIZED; }
// first, massage the existing node so it is in its post-split state

View File

@ -18,11 +18,6 @@
using namespace mozilla;
#ifdef DEBUG
static bool gNoisy = false;
#endif
// note that aEditor is not refcounted
SplitElementTxn::SplitElementTxn()
: EditTxn()
@ -53,16 +48,6 @@ NS_IMETHODIMP SplitElementTxn::Init(nsEditor *aEditor,
NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
{
#ifdef DEBUG
if (gNoisy)
{
printf("%p Do Split of node %p offset %d\n",
static_cast<void*>(this),
static_cast<void*>(mExistingRightNode.get()),
mOffset);
}
#endif
NS_ASSERTION(mExistingRightNode && mEditor, "bad state");
if (!mExistingRightNode || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
@ -74,14 +59,6 @@ NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NULL_POINTER);
mEditor->MarkNodeDirty(mExistingRightNode);
#ifdef DEBUG
if (gNoisy)
{
printf(" created left node = %p\n",
static_cast<void*>(mNewLeftNode.get()));
}
#endif
// get the parent node
mParent = mExistingRightNode->GetParentNode();
NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER);
@ -113,43 +90,13 @@ NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
{
#ifdef DEBUG
if (gNoisy) {
printf("%p Undo Split of existing node %p and new node %p offset %d\n",
static_cast<void*>(this),
static_cast<void*>(mExistingRightNode.get()),
static_cast<void*>(mNewLeftNode.get()),
mOffset);
}
#endif
NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state");
if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) {
return NS_ERROR_NOT_INITIALIZED;
}
// this assumes Do inserted the new node in front of the prior existing node
nsresult rv = mEditor->JoinNodesImpl(mExistingRightNode, mNewLeftNode,
mParent);
#ifdef DEBUG
if (gNoisy)
{
printf("** after join left child node %p into right node %p\n",
static_cast<void*>(mNewLeftNode.get()),
static_cast<void*>(mExistingRightNode.get()));
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
if (NS_SUCCEEDED(rv))
{
if (gNoisy)
{
printf(" left node = %p removed\n",
static_cast<void*>(mNewLeftNode.get()));
}
}
#endif
return rv;
return mEditor->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent);
}
/* redo cannot simply resplit the right node, because subsequent transactions
@ -162,32 +109,12 @@ NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
return NS_ERROR_NOT_INITIALIZED;
}
#ifdef DEBUG
if (gNoisy) {
printf("%p Redo Split of existing node %p and new node %p offset %d\n",
static_cast<void*>(this),
static_cast<void*>(mExistingRightNode.get()),
static_cast<void*>(mNewLeftNode.get()),
mOffset);
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
#endif
// first, massage the existing node so it is in its post-split state
nsCOMPtr<nsIDOMCharacterData>rightNodeAsText = do_QueryInterface(mExistingRightNode);
if (rightNodeAsText)
{
nsresult result = rightNodeAsText->DeleteData(0, mOffset);
NS_ENSURE_SUCCESS(result, result);
#ifdef DEBUG
if (gNoisy)
{
printf("** after delete of text in right text node %p offset %d\n",
static_cast<void*>(rightNodeAsText.get()),
mOffset);
mEditor->DebugDumpContent(); // DEBUG
}
#endif
}
else
{
@ -201,16 +128,6 @@ NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
{
mNewLeftNode->AppendChild(*child, rv);
NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
#ifdef DEBUG
if (gNoisy)
{
printf("** move child node %p from right node %p to left node %p\n",
static_cast<void*>(child),
static_cast<void*>(mExistingRightNode.get()),
static_cast<void*>(mNewLeftNode.get()));
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
#endif
}
child = child->GetNextSibling();
}
@ -218,15 +135,6 @@ NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
// second, re-insert the left node into the tree
ErrorResult rv;
mParent->InsertBefore(*mNewLeftNode, mExistingRightNode, rv);
#ifdef DEBUG
if (gNoisy)
{
printf("** reinsert left child node %p before right node %p\n",
static_cast<void*>(mNewLeftNode.get()),
static_cast<void*>(mExistingRightNode.get()));
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
#endif
return rv.ErrorCode();
}

View File

@ -8,7 +8,7 @@ TEST_DIRS += ['tests']
MODULE = 'editor'
SOURCES += [
UNIFIED_SOURCES += [
'ChangeAttributeTxn.cpp',
'ChangeCSSInlineStyleTxn.cpp',
'CreateElementTxn.cpp',

View File

@ -112,10 +112,6 @@ class nsIOutputStream;
class nsIParserService;
class nsITransferable;
#ifdef NS_DEBUG_EDITOR
static bool gNoisy = false;
#endif
#ifdef DEBUG
#include "nsIDOMHTMLDocument.h" // for nsIDOMHTMLDocument
#endif
@ -779,10 +775,6 @@ nsEditor::SetTransactionManager(nsITransactionManager *aTxnManager)
NS_IMETHODIMP
nsEditor::Undo(uint32_t aCount)
{
#ifdef NS_DEBUG_EDITOR
if (gNoisy) { printf("Editor::Undo ----------\n"); }
#endif
ForceCompositionEnd();
bool hasTxnMgr, hasTransaction = false;
@ -824,10 +816,6 @@ NS_IMETHODIMP nsEditor::CanUndo(bool *aIsEnabled, bool *aCanUndo)
NS_IMETHODIMP
nsEditor::Redo(uint32_t aCount)
{
#ifdef NS_DEBUG_EDITOR
if (gNoisy) { printf("Editor::Redo ----------\n"); }
#endif
bool hasTxnMgr, hasTransaction = false;
CanRedo(&hasTxnMgr, &hasTransaction);
NS_ENSURE_TRUE(hasTransaction, NS_OK);
@ -2714,10 +2702,6 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode,
nsIDOMNode* aNewLeftNode,
nsIDOMNode* aParent)
{
#ifdef NS_DEBUG_EDITOR
if (gNoisy) { printf("SplitNodeImpl: left=%p, right=%p, offset=%d\n", (void*)aNewLeftNode, (void*)aExistingRightNode, aOffset); }
#endif
NS_ASSERTION(((nullptr!=aExistingRightNode) &&
(nullptr!=aNewLeftNode) &&
(nullptr!=aParent)),

View File

@ -8,7 +8,7 @@ TEST_DIRS += ['tests']
MODULE = 'editor'
SOURCES += [
UNIFIED_SOURCES += [
'nsEditProperty.cpp',
'nsHTMLAbsPosition.cpp',
'nsHTMLAnonymousUtils.cpp',

View File

@ -8,7 +8,7 @@ TEST_DIRS += ['tests']
MODULE = 'editor'
SOURCES += [
UNIFIED_SOURCES += [
'nsInternetCiter.cpp',
'nsPlaintextDataTransfer.cpp',
'nsPlaintextEditor.cpp',

View File

@ -6,7 +6,7 @@
MODULE = 'txmgr'
SOURCES += [
UNIFIED_SOURCES += [
'nsTransactionItem.cpp',
'nsTransactionList.cpp',
'nsTransactionManager.cpp',

View File

@ -6,7 +6,7 @@
MODULE = 'txtsvc'
SOURCES += [
UNIFIED_SOURCES += [
'nsFilteredContentIterator.cpp',
'nsTextServicesDocument.cpp',
]

View File

@ -1,4 +1,4 @@
57451
57454
0/nm
0th/pt
1/n1
@ -3828,11 +3828,13 @@ DOS/M
DOT
DP/SM
DPT
DRM
DST
DTP
DUI
DVD
DVDs
DVR/S
DWI
Dacca/M
Dacey/M
@ -38880,6 +38882,7 @@ milky/RTP
mill/MDRSZGJ
millage/M
millenarian
millennia
millennial
millennium/SM
millepede/MS

View File

@ -44,7 +44,8 @@ inline bool IsIgnorableCharacter(PRUnichar ch)
inline bool IsConditionalPunctuation(PRUnichar ch)
{
return (ch == '\'' ||
ch == 0x2019); // RIGHT SINGLE QUOTATION MARK
ch == 0x2019 || // RIGHT SINGLE QUOTATION MARK
ch == 0x00B7); // MIDDLE DOT
}
// mozInlineSpellWordUtil::Init

View File

@ -345,7 +345,7 @@ PathD2D::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule)
sink);
}
RefPtr<PathBuilderD2D> pathBuilder = new PathBuilderD2D(sink, path, mFillRule);
RefPtr<PathBuilderD2D> pathBuilder = new PathBuilderD2D(sink, path, aFillRule);
pathBuilder->mCurrentPoint = aTransform * mEndPoint;

View File

@ -107,6 +107,8 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
bool aIsFirstPaint, uint64_t aFirstPaintLayersId,
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy)
{
mTreeLock.AssertCurrentThreadOwns();
ContainerLayer* container = aLayer->AsContainerLayer();
AsyncPanZoomController* apzc = nullptr;
if (container) {
@ -315,7 +317,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
return result;
}
AsyncPanZoomController*
already_AddRefed<AsyncPanZoomController>
APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
ScreenPoint aPoint)
{
@ -324,7 +326,7 @@ APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
// Reset the cached apz transform
mCachedTransformToApzcForInputBlock = transformToApzc;
if (!apzc) {
return nullptr;
return apzc.forget();
}
for (size_t i = 1; i < aEvent.touches.Length(); i++) {
nsIntPoint point = aEvent.touches[i]->mRefPoint;
@ -341,7 +343,7 @@ APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
// Cache apz transform so it can be used for future events in this block.
GetInputTransforms(apzc, mCachedTransformToApzcForInputBlock, transformToGecko);
}
return apzc.get();
return apzc.forget();
}
nsEventStatus
@ -349,6 +351,8 @@ APZCTreeManager::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
WidgetTouchEvent* aOutEvent)
{
MOZ_ASSERT(NS_IsMainThread());
nsEventStatus ret = nsEventStatus_eIgnore;
if (!aEvent.touches.Length()) {
return ret;
@ -421,6 +425,8 @@ APZCTreeManager::ProcessMouseEvent(const WidgetMouseEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
WidgetMouseEvent* aOutEvent)
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y));
if (!apzc) {
return nsEventStatus_eIgnore;
@ -441,6 +447,8 @@ APZCTreeManager::ProcessEvent(const WidgetInputEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
WidgetInputEvent* aOutEvent)
{
MOZ_ASSERT(NS_IsMainThread());
// Transform the refPoint
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y));
if (!apzc) {
@ -645,6 +653,8 @@ APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
AsyncPanZoomController*
APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid) {
mTreeLock.AssertCurrentThreadOwns();
// This walks the tree in depth-first, reverse order, so that it encounters
// APZCs front-to-back on the screen.
for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
@ -663,6 +673,8 @@ APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableL
AsyncPanZoomController*
APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint)
{
mTreeLock.AssertCurrentThreadOwns();
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
// explained in the comment on GetInputTransforms. This function will recurse with aApzc at L and P, and the
// comments explain what values are stored in the variables at these two levels. All the comments
@ -796,6 +808,8 @@ void
APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
gfx3DMatrix& aTransformToGeckoOut)
{
MonitorAutoLock lock(mTreeLock);
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
// explained in the comment above. This function is called with aApzc at L, and the loop
// below performs one iteration, where parent is at P. The comments explain what values are stored
@ -835,9 +849,12 @@ APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix&
}
}
AsyncPanZoomController*
already_AddRefed<AsyncPanZoomController>
APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2)
{
MonitorAutoLock lock(mTreeLock);
nsRefPtr<AsyncPanZoomController> ancestor;
// If either aApzc1 or aApzc2 is null, min(depth1, depth2) will be 0 and this function
// will return null.
@ -866,7 +883,8 @@ APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomCont
// either APZC, and return the the first common ancestor encountered.
while (true) {
if (aApzc1 == aApzc2) {
return aApzc1;
ancestor = aApzc1;
break;
}
if (depth1 <= 0) {
break;
@ -874,16 +892,18 @@ APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomCont
aApzc1 = aApzc1->GetParent();
aApzc2 = aApzc2->GetParent();
}
return nullptr;
return ancestor.forget();
}
AsyncPanZoomController*
already_AddRefed<AsyncPanZoomController>
APZCTreeManager::RootAPZCForLayersId(AsyncPanZoomController* aApzc)
{
while (aApzc && !aApzc->IsRootForLayersId()) {
aApzc = aApzc->GetParent();
MonitorAutoLock lock(mTreeLock);
nsRefPtr<AsyncPanZoomController> apzc = aApzc;
while (apzc && !apzc->IsRootForLayersId()) {
apzc = apzc->GetParent();
}
return aApzc;
return apzc.forget();
}
}

View File

@ -310,9 +310,9 @@ private:
/* Helpers */
AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint);
AsyncPanZoomController* CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
AsyncPanZoomController* RootAPZCForLayersId(AsyncPanZoomController* aApzc);
AsyncPanZoomController* GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent, ScreenPoint aPoint);
already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent, ScreenPoint aPoint);
nsEventStatus ProcessTouchEvent(const WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetTouchEvent* aOutEvent);
nsEventStatus ProcessMouseEvent(const WidgetMouseEvent& mouseEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetMouseEvent* aOutEvent);
nsEventStatus ProcessEvent(const WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetInputEvent* aOutEvent);

View File

@ -0,0 +1 @@
<html xmlns="http://www.w3.org/1999/xhtml"><msqrt xmlns="http://www.w3.org/1998/Math/MathML"><mpadded depth="+98774970791px"/></msqrt></html>

View File

@ -85,6 +85,7 @@ load 580233-1.html
load 580719-1.html
load 594654-1.xhtml
load 595727-1.html
load 624198.xhtml
load 633453-1.html
load 633322-1.html
load 665218.html

View File

@ -3344,11 +3344,14 @@ gfxFont::ShapeTextWithoutWordCache(gfxContext *aContext,
}
// fragment was terminated by an invalid char: skip it,
// unless it's a control char that we want to show as a hexbox,
// but record where TAB or NEWLINE occur
if (ch == '\t') {
aTextRun->SetIsTab(aOffset + i);
} else if (ch == '\n') {
aTextRun->SetIsNewline(aOffset + i);
} else if ((ch & 0x7f) < 0x20 || ch == 0x7f) {
aTextRun->SetMissingGlyph(aOffset + i, ch, this);
}
fragStart = i + 1;
}
@ -3485,11 +3488,14 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
"how did we get here except via an invalid char?");
// word was terminated by an invalid char: skip it,
// unless it's a control char that we want to show as a hexbox,
// but record where TAB or NEWLINE occur
if (ch == '\t') {
aTextRun->SetIsTab(aRunStart + i);
} else if (ch == '\n') {
aTextRun->SetIsNewline(aRunStart + i);
} else if ((ch & 0x7f) < 0x20 || ch == 0x7f) {
aTextRun->SetMissingGlyph(aRunStart + i, ch, this);
}
hash = 0;

View File

@ -1602,33 +1602,51 @@ class MutableValueOperations : public UnbarrieredMutableValueOperations<Outer>
* type-querying, value-extracting, and mutating operations.
*/
template <>
class HeapBase<JS::Value> : public UnbarrieredMutableValueOperations<JS::Heap<JS::Value> >
class HeapBase<JS::Value> : public ValueOperations<JS::Heap<JS::Value> >
{
typedef JS::Heap<JS::Value> Outer;
friend class ValueOperations<Outer>;
friend class UnbarrieredMutableValueOperations<Outer>;
const JS::Value * extract() const { return static_cast<const Outer*>(this)->address(); }
JS::Value * extractMutable() { return static_cast<Outer*>(this)->unsafeGet(); }
/*
* Setters that potentially change the value to a GC thing from a non-GC
* thing must call JS::Heap::set() to trigger the post barrier.
*
* Changing from a GC thing to a non-GC thing value will leave the heap
* value in the store buffer, but it will be ingored so this is not a
* problem.
*/
void setBarriered(const JS::Value &v) {
static_cast<JS::Heap<JS::Value> *>(this)->set(v);
}
public:
void setNull() { setBarriered(JS::NullValue()); }
void setUndefined() { setBarriered(JS::UndefinedValue()); }
void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); }
void setDouble(double d) { setBarriered(JS::DoubleValue(d)); }
void setNaN() { setDouble(JS::GenericNaN()); }
void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); }
void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); }
void setString(JSString *str) { setBarriered(JS::StringValue(str)); }
void setString(const JS::Anchor<JSString *> &str) { setBarriered(JS::StringValue(str.get())); }
void setObject(JSObject &obj) { setBarriered(JS::ObjectValue(obj)); }
bool setNumber(uint32_t ui) {
if (ui > JSVAL_INT_MAX) {
setDouble((double)ui);
return false;
} else {
setInt32((int32_t)ui);
return true;
}
}
bool setNumber(double d) {
int32_t i;
if (mozilla::DoubleIsInt32(d, &i)) {
setInt32(i);
return true;
}
setDouble(d);
return false;
}
void setObjectOrNull(JSObject *arg) {
if (arg)
setObject(*arg);

View File

@ -16,6 +16,8 @@ MacroAssemblerX86Common::SSECheckState MacroAssemblerX86Common::s_sseCheckState
#ifdef DEBUG
bool MacroAssemblerX86Common::s_floatingPointDisabled = false;
bool MacroAssemblerX86Common::s_SSE3Disabled = false;
bool MacroAssemblerX86Common::s_SSE4Disabled = false;
#endif
#endif /* WTF_CPU_X86 || WTF_CPU_X86_64 */

View File

@ -1403,6 +1403,13 @@ private:
s_sseCheckState = HasSSE;
else
s_sseCheckState = NoSSE;
#ifdef DEBUG
if (s_sseCheckState >= HasSSE4_1 && s_SSE4Disabled)
s_sseCheckState = HasSSE3;
if (s_sseCheckState >= HasSSE3 && s_SSE3Disabled)
s_sseCheckState = HasSSE2;
#endif
}
#if WTF_CPU_X86
@ -1505,11 +1512,19 @@ private:
#ifdef DEBUG
static bool s_floatingPointDisabled;
static bool s_SSE3Disabled;
static bool s_SSE4Disabled;
public:
static void SetFloatingPointDisabled() {
s_floatingPointDisabled = true;
}
static void SetSSE3Disabled() {
s_SSE3Disabled = true;
}
static void SetSSE4Disabled() {
s_SSE4Disabled = true;
}
#endif
};

View File

@ -529,6 +529,7 @@ const JSPropertySpec ArrayType::typedObjectProperties[] = {
const JSFunctionSpec ArrayType::typedObjectMethods[] = {
JS_FN("subarray", ArrayType::subarray, 2, 0),
{"forEach", {nullptr, nullptr}, 1, 0, "ArrayForEach"},
{"redimension", {nullptr, nullptr}, 1, 0, "TypedArrayRedimension"},
JS_FS_END
};

View File

@ -415,6 +415,73 @@ function TypeObjectEquivalent(otherTypeObj) {
return TYPE_TYPE_REPR(this) === TYPE_TYPE_REPR(otherTypeObj);
}
// TypedArray.redimension(newArrayType)
//
// Method that "repackages" the data from this array into a new typed
// object whose type is `newArrayType`. Once you strip away all the
// outer array dimensions, the type of `this` array and `newArrayType`
// must share the same innermost element type. Moreover, those
// stripped away dimensions must amount to the same total number of
// elements.
//
// For example, given two equivalent types `T` and `U`, it is legal to
// interconvert between arrays types like:
// T[32]
// U[2][16]
// U[2][2][8]
// Because they all share the same total number (32) of equivalent elements.
// But it would be illegal to convert `T[32]` to `U[31]` or `U[2][17]`, since
// the number of elements differs. And it's just plain incompatible to convert
// if the base element types are not equivalent.
//
// Warning: user exposed!
function TypedArrayRedimension(newArrayType) {
if (!IsObject(this) || !ObjectIsTypedDatum(this))
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
if (!IsObject(newArrayType) || !ObjectIsTypeObject(newArrayType))
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1, "type object");
// Peel away the outermost array layers from the type of `this` to find
// the core element type. In the process, count the number of elements.
var oldArrayType = DATUM_TYPE_OBJ(this);
var oldElementType = oldArrayType;
var oldElementCount = 1;
while (REPR_KIND(TYPE_TYPE_REPR(oldElementType)) == JS_TYPEREPR_ARRAY_KIND) {
oldElementCount *= oldElementType.length;
oldElementType = oldElementType.elementType;
}
// Peel away the outermost array layers from `newArrayType`. In the
// process, count the number of elements.
var newElementType = newArrayType;
var newElementCount = 1;
while (REPR_KIND(TYPE_TYPE_REPR(newElementType)) == JS_TYPEREPR_ARRAY_KIND) {
newElementCount *= newElementType.length;
newElementType = newElementType.elementType;
}
// Check that the total number of elements does not change.
if (oldElementCount !== newElementCount) {
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1,
"New number of elements does not match old number of elements");
}
// Check that the element types are equivalent.
if (TYPE_TYPE_REPR(oldElementType) !== TYPE_TYPE_REPR(newElementType)) {
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1,
"New element type is not equivalent to old element type");
}
// Together, this should imply that the sizes are unchanged.
assert(REPR_SIZE(TYPE_TYPE_REPR(oldArrayType)) ==
REPR_SIZE(TYPE_TYPE_REPR(newArrayType)),
"Byte sizes should be equal");
// Rewrap the data from `this` in a new type.
return NewDerivedTypedDatum(newArrayType, this, 0);
}
///////////////////////////////////////////////////////////////////////////
// Handles
//

View File

@ -800,7 +800,7 @@ else # !WINNT || GNU_CC
endif # WINNT && !GNU_CC
ifdef ENABLE_STRIP
$(STRIP) $@
$(STRIP) $(STRIP_FLAGS) $@
endif
ifdef MOZ_POST_PROGRAM_COMMAND
$(MOZ_POST_PROGRAM_COMMAND) $@
@ -856,7 +856,7 @@ else
endif # WINNT && !GNU_CC
ifdef ENABLE_STRIP
$(STRIP) $@
$(STRIP) $(STRIP_FLAGS) $@
endif
ifdef MOZ_POST_PROGRAM_COMMAND
$(MOZ_POST_PROGRAM_COMMAND) $@
@ -883,7 +883,6 @@ $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(REPORT_BUILD)
$(RM) $(LIBRARY)
$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(SHARED_LIBRARY_LIBS)
$(RANLIB) $@
$(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
# When we only build a library descriptor, blow out any existing library
@ -917,14 +916,12 @@ $(IMPORT_LIBRARY): $(SHARED_LIBRARY)
$(REPORT_BUILD)
$(RM) $@
$(IMPLIB) $@ $^
$(RANLIB) $@
endif # OS/2
$(HOST_LIBRARY): $(HOST_OBJS) Makefile
$(REPORT_BUILD)
$(RM) $@
$(EXPAND_LIBS_EXEC) --extract -- $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
$(HOST_RANLIB) $@
ifdef HAVE_DTRACE
ifndef XP_MACOSX
@ -975,7 +972,7 @@ endif # WINNT && !GCC
@$(RM) foodummyfilefoo $(DELETE_AFTER_LINK)
chmod +x $@
ifdef ENABLE_STRIP
$(STRIP) $@
$(STRIP) $(STRIP_FLAGS) $@
endif
ifdef MOZ_POST_DSO_LIB_COMMAND
$(MOZ_POST_DSO_LIB_COMMAND) $@

View File

@ -284,7 +284,7 @@ dnl to use the cross-compile setup for now
dnl ========================================================
dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269)
AR_FLAGS='cr $@'
AR_FLAGS='crs $@'
if test "$COMPILE_ENVIRONMENT"; then

View File

@ -59,6 +59,7 @@ struct frontend::StmtInfoBCE : public StmtInfoBase
ptrdiff_t update; /* loop update offset (top if none) */
ptrdiff_t breaks; /* offset of last break in loop */
ptrdiff_t continues; /* offset of last continue in loop */
uint32_t blockScopeIndex; /* index of scope in BlockScopeArray */
StmtInfoBCE(ExclusiveContext *cx) : StmtInfoBase(cx) {}
@ -100,10 +101,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
atomIndices(sc->context),
firstLine(lineNum),
stackDepth(0), maxStackDepth(0),
tryNoteList(sc->context),
arrayCompDepth(0),
emitLevel(0),
constList(sc->context),
tryNoteList(sc->context),
blockScopeList(sc->context),
typesetCount(0),
hasSingletons(false),
emittingForInit(false),
@ -686,13 +688,23 @@ EnclosingStaticScope(BytecodeEmitter *bce)
}
// Push a block scope statement and link blockObj into bce->blockChain.
static void
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StaticBlockObject &blockObj,
static bool
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
ptrdiff_t top)
{
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
PushStatementBCE(bce, stmt, STMT_BLOCK, top);
unsigned scopeObjectIndex = bce->objectList.add(objbox);
stmt->blockScopeIndex = bce->blockScopeList.length();
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset()))
return false;
blockObj.initEnclosingStaticScope(EnclosingStaticScope(bce));
FinishPushBlockScope(bce, stmt, blockObj);
return true;
}
// Patches |breaks| and |continues| unless the top statement info record
@ -707,6 +719,10 @@ PopStatementBCE(ExclusiveContext *cx, BytecodeEmitter *bce)
{
return false;
}
if (stmt->isBlockScope)
bce->blockScopeList.recordEnd(stmt->blockScopeIndex, bce->offset());
FinishPopStatement(bce);
return true;
}
@ -770,10 +786,17 @@ EmitAtomOp(ExclusiveContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
}
static bool
EmitObjectOp(ExclusiveContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmitter *bce)
{
JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
return EmitIndex32(cx, op, bce->objectList.add(objbox), bce);
JS_ASSERT(index < bce->objectList.length);
return EmitIndex32(cx, op, index, bce);
}
static bool
EmitObjectOp(ExclusiveContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
{
return EmitInternedObjectOp(cx, bce->objectList.add(objbox), op, bce);
}
static bool
@ -1061,7 +1084,15 @@ static bool
EmitEnterBlock(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
{
JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
if (!EmitObjectOp(cx, pn->pn_objbox, op, bce))
StmtInfoBCE *stmt = bce->topStmt;
JS_ASSERT(stmt->type == STMT_BLOCK || stmt->type == STMT_SWITCH);
JS_ASSERT(stmt->isBlockScope);
JS_ASSERT(stmt->blockScopeIndex == bce->blockScopeList.length() - 1);
JS_ASSERT(bce->blockScopeList.list[stmt->blockScopeIndex].length == 0);
uint32_t scopeObjectIndex = bce->blockScopeList.list[stmt->blockScopeIndex].index;
JS_ASSERT(scopeObjectIndex == bce->objectList.length - 1);
JS_ASSERT(pn->pn_objbox == bce->objectList.lastbox);
if (!EmitInternedObjectOp(cx, scopeObjectIndex, op, bce))
return false;
Rooted<StaticBlockObject*> blockObj(cx, &pn->pn_objbox->object->as<StaticBlockObject>());
@ -2305,7 +2336,8 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return false;
if (pn2->isKind(PNK_LEXICALSCOPE)) {
PushBlockScopeBCE(bce, &stmtInfo, pn2->pn_objbox->object->as<StaticBlockObject>(), -1);
if (!PushBlockScopeBCE(bce, &stmtInfo, pn2->pn_objbox, -1))
return false;
stmtInfo.type = STMT_SWITCH;
if (!EmitEnterBlock(cx, bce, pn2, JSOP_ENTERLET1))
return false;
@ -4193,7 +4225,8 @@ EmitLet(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
}
StmtInfoBCE stmtInfo(cx);
PushBlockScopeBCE(bce, &stmtInfo, *blockObj, bce->offset());
if (!PushBlockScopeBCE(bce, &stmtInfo, letBody->pn_objbox, bce->offset()))
return false;
DebugOnly<ptrdiff_t> bodyBegin = bce->offset();
if (!EmitEnterBlock(cx, bce, letBody, JSOP_ENTERLET0))
@ -4226,7 +4259,8 @@ EmitLexicalScope(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
ObjectBox *objbox = pn->pn_objbox;
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
size_t slots = blockObj.slotCount();
PushBlockScopeBCE(bce, &stmtInfo, blockObj, bce->offset());
if (!PushBlockScopeBCE(bce, &stmtInfo, objbox, bce->offset()))
return false;
if (!EmitEnterBlock(cx, bce, pn, JSOP_ENTERBLOCK))
return false;
@ -4316,7 +4350,8 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
// Enter the block before the loop body, after evaluating the obj.
StmtInfoBCE letStmt(cx);
if (letDecl) {
PushBlockScopeBCE(bce, &letStmt, *blockObj, bce->offset());
if (!PushBlockScopeBCE(bce, &letStmt, pn1->pn_objbox, bce->offset()))
return false;
letStmt.isForLetBlock = true;
if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET2))
return false;
@ -4492,7 +4527,8 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
/* Enter the block before the loop body, after evaluating the obj. */
StmtInfoBCE letStmt(cx);
if (letDecl) {
PushBlockScopeBCE(bce, &letStmt, *blockObj, bce->offset());
if (!PushBlockScopeBCE(bce, &letStmt, pn1->pn_objbox, bce->offset()))
return false;
letStmt.isForLetBlock = true;
if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1))
return false;
@ -6775,25 +6811,8 @@ frontend::FinishTakingSrcNotes(ExclusiveContext *cx, BytecodeEmitter *bce, jssrc
return true;
}
bool
CGTryNoteList::append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end)
{
JS_ASSERT(unsigned(uint16_t(stackDepth)) == stackDepth);
JS_ASSERT(start <= end);
JS_ASSERT(size_t(uint32_t(start)) == start);
JS_ASSERT(size_t(uint32_t(end)) == end);
JSTryNote note;
note.kind = kind;
note.stackDepth = uint16_t(stackDepth);
note.start = uint32_t(start);
note.length = uint32_t(end - start);
return list.append(note);
}
void
CGTryNoteList::finish(TryNoteArray *array)
CGConstList::finish(ConstArray *array)
{
JS_ASSERT(length() == array->length);
@ -6878,8 +6897,56 @@ CGObjectList::finish(ObjectArray *array)
JS_ASSERT(cursor == array->vector);
}
bool
CGTryNoteList::append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end)
{
JS_ASSERT(unsigned(uint16_t(stackDepth)) == stackDepth);
JS_ASSERT(start <= end);
JS_ASSERT(size_t(uint32_t(start)) == start);
JS_ASSERT(size_t(uint32_t(end)) == end);
JSTryNote note;
note.kind = kind;
note.stackDepth = uint16_t(stackDepth);
note.start = uint32_t(start);
note.length = uint32_t(end - start);
return list.append(note);
}
void
CGConstList::finish(ConstArray *array)
CGTryNoteList::finish(TryNoteArray *array)
{
JS_ASSERT(length() == array->length);
for (unsigned i = 0; i < length(); i++)
array->vector[i] = list[i];
}
bool
CGBlockScopeList::append(uint32_t scopeObject, uint32_t offset)
{
BlockScopeNote note;
mozilla::PodZero(&note);
note.index = scopeObject;
note.start = offset;
return list.append(note);
}
void
CGBlockScopeList::recordEnd(uint32_t index, uint32_t offset)
{
JS_ASSERT(index < length());
JS_ASSERT(offset >= list[index].start);
JS_ASSERT(list[index].length == 0);
list[index].length = offset - list[index].start;
}
void
CGBlockScopeList::finish(BlockScopeArray *array)
{
JS_ASSERT(length() == array->length);

View File

@ -28,13 +28,13 @@ template <typename ParseHandler> class Parser;
class SharedContext;
class TokenStream;
struct CGTryNoteList {
Vector<JSTryNote> list;
CGTryNoteList(ExclusiveContext *cx) : list(cx) {}
bool append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end);
class CGConstList {
Vector<Value> list;
public:
CGConstList(ExclusiveContext *cx) : list(cx) {}
bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
size_t length() const { return list.length(); }
void finish(TryNoteArray *array);
void finish(ConstArray *array);
};
struct CGObjectList {
@ -48,13 +48,23 @@ struct CGObjectList {
void finish(ObjectArray *array);
};
class CGConstList {
Vector<Value> list;
public:
CGConstList(ExclusiveContext *cx) : list(cx) {}
bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
struct CGTryNoteList {
Vector<JSTryNote> list;
CGTryNoteList(ExclusiveContext *cx) : list(cx) {}
bool append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end);
size_t length() const { return list.length(); }
void finish(ConstArray *array);
void finish(TryNoteArray *array);
};
struct CGBlockScopeList {
Vector<BlockScopeNote> list;
CGBlockScopeList(ExclusiveContext *cx) : list(cx) {}
bool append(uint32_t scopeObject, uint32_t offset);
void recordEnd(uint32_t index, uint32_t offset);
size_t length() const { return list.length(); }
void finish(BlockScopeArray *array);
};
struct StmtInfoBCE;
@ -104,8 +114,6 @@ struct BytecodeEmitter
int stackDepth; /* current stack depth in script frame */
unsigned maxStackDepth; /* maximum stack depth so far */
CGTryNoteList tryNoteList; /* list of emitted try notes */
unsigned arrayCompDepth; /* stack depth of array in comprehension */
unsigned emitLevel; /* js::frontend::EmitTree recursion level */
@ -115,6 +123,8 @@ struct BytecodeEmitter
CGObjectList objectList; /* list of emitted objects */
CGObjectList regexpList; /* list of emitted regexp that will be
cloned during execution */
CGTryNoteList tryNoteList; /* list of emitted try notes */
CGBlockScopeList blockScopeList;/* list of emitted block scope notes */
uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */

View File

@ -164,7 +164,7 @@ def main(argv):
flags = [
[], # no flags, normal baseline and ion
['--ion-eager'], # implies --baseline-eager
['--ion-eager', '--ion-check-range-analysis'],
['--ion-eager', '--ion-check-range-analysis', '--no-sse3'],
['--baseline-eager'],
['--baseline-eager', '--no-ti', '--no-fpu'],
['--no-baseline', '--no-ion'],

View File

@ -1,6 +1,18 @@
(function() {
"use asm"
"use asm";
function f() {
i((1.5 != 2.) ? 3 : 0)
i((1.5 != 2.) ? 3 : 0);
}
return f;
})();
// Bug 933104
(function() {
"use asm";
function f(x) {
x = +x;
x = -2.;
(x > -1.5) ? 0 : 0;
}
return f;
})()

View File

@ -1,3 +1,5 @@
if (typeof ParallelArray === "undefined")
quit();
x = ParallelArray([1942], function() {})
x + watch.call(x, "length", (function() {}));

View File

@ -113,12 +113,12 @@ BacktrackingAllocator::go()
return false;
IonSpew(IonSpew_RegAlloc, "Liveness analysis complete");
if (IonSpewEnabled(IonSpew_RegAlloc))
dumpLiveness();
if (!init())
return false;
if (IonSpewEnabled(IonSpew_RegAlloc))
dumpLiveness();
if (!allocationQueue.reserve(graph.numVirtualRegisters() * 3 / 2))
return false;
@ -317,7 +317,9 @@ BacktrackingAllocator::tryGroupReusedRegister(uint32_t def, uint32_t use)
if (!newIntervals.append(preInterval) || !newIntervals.append(postInterval))
return false;
if (!distributeUses(interval, newIntervals) || !split(interval, newIntervals))
distributeUses(interval, newIntervals);
if (!split(interval, newIntervals))
return false;
JS_ASSERT(usedReg.numIntervals() == 2);
@ -331,7 +333,9 @@ bool
BacktrackingAllocator::groupAndQueueRegisters()
{
// Try to group registers with their reused inputs.
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
// Virtual register number 0 is unused.
JS_ASSERT(vregs[0u].numIntervals() == 0);
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
BacktrackingVirtualRegister &reg = vregs[i];
if (!reg.numIntervals())
continue;
@ -357,7 +361,9 @@ BacktrackingAllocator::groupAndQueueRegisters()
}
}
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
// Virtual register number 0 is unused.
JS_ASSERT(vregs[0u].numIntervals() == 0);
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
if (mir->shouldCancel("Backtracking Enqueue Registers"))
return false;
@ -491,19 +497,17 @@ BacktrackingAllocator::processInterval(LiveInterval *interval)
return true;
}
}
}
// Failed to allocate a register for this interval.
if (attempt < MAX_ATTEMPTS &&
canAllocate &&
!fixed &&
conflict &&
computeSpillWeight(conflict) < computeSpillWeight(interval))
{
if (!evictInterval(conflict))
return false;
continue;
// Failed to allocate a register for this interval.
if (attempt < MAX_ATTEMPTS &&
!fixed &&
conflict &&
computeSpillWeight(conflict) < computeSpillWeight(interval))
{
if (!evictInterval(conflict))
return false;
continue;
}
}
// A minimal interval cannot be split any further. If we try to split
@ -757,7 +761,7 @@ BacktrackingAllocator::evictInterval(LiveInterval *interval)
return allocationQueue.insert(QueueItem(interval, priority));
}
bool
void
BacktrackingAllocator::distributeUses(LiveInterval *interval,
const LiveIntervalVector &newIntervals)
{
@ -782,8 +786,6 @@ BacktrackingAllocator::distributeUses(LiveInterval *interval,
}
addInterval->addUse(new UsePosition(iter->use, iter->pos));
}
return true;
}
bool
@ -791,7 +793,7 @@ BacktrackingAllocator::split(LiveInterval *interval,
const LiveIntervalVector &newIntervals)
{
if (IonSpewEnabled(IonSpew_RegAlloc)) {
IonSpew(IonSpew_RegAlloc, "splitting interval v%u %s:",
IonSpew(IonSpew_RegAlloc, "splitting interval v%u %s into:",
interval->vreg(), IntervalString(interval));
for (size_t i = 0; i < newIntervals.length(); i++)
IonSpew(IonSpew_RegAlloc, " %s", IntervalString(newIntervals[i]));
@ -885,7 +887,9 @@ BacktrackingAllocator::spill(LiveInterval *interval)
bool
BacktrackingAllocator::resolveControlFlow()
{
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
// Virtual register number 0 is unused.
JS_ASSERT(vregs[0u].numIntervals() == 0);
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
BacktrackingVirtualRegister *reg = &vregs[i];
if (mir->shouldCancel("Backtracking Resolve Control Flow (vreg loop)"))
@ -1001,11 +1005,11 @@ BacktrackingAllocator::isReusedInput(LUse *use, LInstruction *ins, bool consider
}
bool
BacktrackingAllocator::isRegisterUse(LUse *use, LInstruction *ins)
BacktrackingAllocator::isRegisterUse(LUse *use, LInstruction *ins, bool considerCopy)
{
switch (use->policy()) {
case LUse::ANY:
return isReusedInput(use, ins);
return isReusedInput(use, ins, considerCopy);
case LUse::REGISTER:
case LUse::FIXED:
@ -1035,7 +1039,9 @@ BacktrackingAllocator::isRegisterDefinition(LiveInterval *interval)
bool
BacktrackingAllocator::reifyAllocations()
{
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
// Virtual register number 0 is unused.
JS_ASSERT(vregs[0u].numIntervals() == 0);
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
VirtualRegister *reg = &vregs[i];
if (mir->shouldCancel("Backtracking Reify Allocations (main loop)"))
@ -1095,7 +1101,9 @@ BacktrackingAllocator::populateSafepoints()
{
size_t firstSafepoint = 0;
for (uint32_t i = 0; i < vregs.numVirtualRegisters(); i++) {
// Virtual register number 0 is unused.
JS_ASSERT(!vregs[0u].def());
for (uint32_t i = 1; i < vregs.numVirtualRegisters(); i++) {
BacktrackingVirtualRegister *reg = &vregs[i];
if (!reg->def() || (!IsTraceable(reg) && !IsSlotsOrElements(reg) && !IsNunbox(reg)))
@ -1132,7 +1140,7 @@ BacktrackingAllocator::populateSafepoints()
for (size_t k = 0; k < reg->numIntervals(); k++) {
LiveInterval *interval = reg->getInterval(k);
if (!interval->covers(inputOf(ins)))
if (!interval->covers(outputOf(ins)))
continue;
LAllocation *a = interval->getAllocation();
@ -1172,7 +1180,10 @@ void
BacktrackingAllocator::dumpRegisterGroups()
{
fprintf(stderr, "Register groups:\n");
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
// Virtual register number 0 is unused.
JS_ASSERT(!vregs[0u].group());
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
VirtualRegisterGroup *group = vregs[i].group();
if (group && i == group->canonicalReg()) {
for (size_t j = 0; j < group->registers.length(); j++)
@ -1200,11 +1211,12 @@ BacktrackingAllocator::dumpLiveness()
for (size_t i = 0; i < block->numPhis(); i++) {
LPhi *phi = block->getPhi(i);
fprintf(stderr, "[%u,%u Phi v%u <-",
inputOf(phi).pos(), outputOf(phi).pos(),
// Don't print the inputOf for phi nodes, since it's never used.
fprintf(stderr, "[,%u Phi [def v%u] <-",
outputOf(phi).pos(),
phi->getDef(0)->virtualRegister());
for (size_t j = 0; j < phi->numOperands(); j++)
fprintf(stderr, " v%u", phi->getOperand(j)->toUse()->virtualRegister());
fprintf(stderr, " %s", phi->getOperand(j)->toString());
fprintf(stderr, "]\n");
}
@ -1224,10 +1236,8 @@ BacktrackingAllocator::dumpLiveness()
fprintf(stderr, " [def v%u]", def->virtualRegister());
}
for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) {
if (alloc->isUse())
fprintf(stderr, " [use v%u]", alloc->toUse()->virtualRegister());
}
for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next())
fprintf(stderr, " [use %s]", alloc->toString());
fprintf(stderr, "\n");
}
@ -1236,9 +1246,12 @@ BacktrackingAllocator::dumpLiveness()
fprintf(stderr, "\nLive Ranges:\n\n");
for (size_t i = 0; i < AnyRegister::Total; i++)
fprintf(stderr, "reg %s: %s\n", AnyRegister::FromCode(i).name(), IntervalString(fixedIntervals[i]));
if (registers[i].allocatable)
fprintf(stderr, "reg %s: %s\n", AnyRegister::FromCode(i).name(), IntervalString(fixedIntervals[i]));
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
// Virtual register number 0 is unused.
JS_ASSERT(vregs[0u].numIntervals() == 0);
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
fprintf(stderr, "v%lu:", static_cast<unsigned long>(i));
VirtualRegister &vreg = vregs[i];
for (size_t j = 0; j < vreg.numIntervals(); j++) {
@ -1259,9 +1272,13 @@ struct BacktrackingAllocator::PrintLiveIntervalRange
void operator()(const AllocatedRange &item)
{
if (item.range == item.interval->getRange(0)) {
fprintf(stderr, " v%u: %s\n",
item.interval->hasVreg() ? item.interval->vreg() : 0,
IntervalString(item.interval));
if (item.interval->hasVreg())
fprintf(stderr, " v%u: %s\n",
item.interval->vreg(),
IntervalString(item.interval));
else
fprintf(stderr, " fixed: %s\n",
IntervalString(item.interval));
}
}
};
@ -1273,7 +1290,9 @@ BacktrackingAllocator::dumpAllocations()
#ifdef DEBUG
fprintf(stderr, "Allocations:\n");
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
// Virtual register number 0 is unused.
JS_ASSERT(vregs[0u].numIntervals() == 0);
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
fprintf(stderr, "v%lu:", static_cast<unsigned long>(i));
VirtualRegister &vreg = vregs[i];
for (size_t j = 0; j < vreg.numIntervals(); j++) {
@ -1288,8 +1307,10 @@ BacktrackingAllocator::dumpAllocations()
fprintf(stderr, "\n");
for (size_t i = 0; i < AnyRegister::Total; i++) {
fprintf(stderr, "reg %s:\n", AnyRegister::FromCode(i).name());
registers[i].allocations.forEach(PrintLiveIntervalRange());
if (registers[i].allocatable) {
fprintf(stderr, "reg %s:\n", AnyRegister::FromCode(i).name());
registers[i].allocations.forEach(PrintLiveIntervalRange());
}
}
fprintf(stderr, "\n");
@ -1342,7 +1363,7 @@ BacktrackingAllocator::minimalDef(const LiveInterval *interval, LInstruction *in
{
// Whether interval is a minimal interval capturing a definition at ins.
return (interval->end() <= minimalDefEnd(ins).next()) &&
(interval->start() == inputOf(ins) || interval->start() == outputOf(ins));
((!ins->isPhi() && interval->start() == inputOf(ins)) || interval->start() == outputOf(ins));
}
bool
@ -1530,10 +1551,10 @@ BacktrackingAllocator::trySplitAcrossHotcode(LiveInterval *interval, bool *succe
if (postInterval && !newIntervals.append(postInterval))
return false;
distributeUses(interval, newIntervals);
*success = true;
return distributeUses(interval, newIntervals) &&
split(interval, newIntervals) &&
requeueIntervals(newIntervals);
return split(interval, newIntervals) && requeueIntervals(newIntervals);
}
bool
@ -1555,22 +1576,9 @@ BacktrackingAllocator::trySplitAfterLastRegisterUse(LiveInterval *interval, bool
JS_ASSERT(iter->pos >= lastUse);
lastUse = inputOf(ins);
switch (use->policy()) {
case LUse::ANY:
if (isReusedInput(iter->use, ins, /* considerCopy = */ true)) {
lastRegisterFrom = inputOf(ins);
lastRegisterTo = iter->pos.next();
}
break;
case LUse::REGISTER:
case LUse::FIXED:
if (isRegisterUse(use, ins, /* considerCopy = */ true)) {
lastRegisterFrom = inputOf(ins);
lastRegisterTo = iter->pos.next();
break;
default:
break;
}
}
@ -1602,10 +1610,10 @@ BacktrackingAllocator::trySplitAfterLastRegisterUse(LiveInterval *interval, bool
if (!newIntervals.append(preInterval) || !newIntervals.append(postInterval))
return false;
distributeUses(interval, newIntervals);
*success = true;
return distributeUses(interval, newIntervals) &&
split(interval, newIntervals) &&
requeueIntervals(newIntervals);
return split(interval, newIntervals) && requeueIntervals(newIntervals);
}
bool

View File

@ -192,13 +192,13 @@ class BacktrackingAllocator : public LiveRangeAllocator<BacktrackingVirtualRegis
bool tryAllocateGroupRegister(PhysicalRegister &r, VirtualRegisterGroup *group,
bool *psuccess, bool *pfixed, LiveInterval **pconflicting);
bool evictInterval(LiveInterval *interval);
bool distributeUses(LiveInterval *interval, const LiveIntervalVector &newIntervals);
void distributeUses(LiveInterval *interval, const LiveIntervalVector &newIntervals);
bool split(LiveInterval *interval, const LiveIntervalVector &newIntervals);
bool requeueIntervals(const LiveIntervalVector &newIntervals);
void spill(LiveInterval *interval);
bool isReusedInput(LUse *use, LInstruction *ins, bool considerCopy = false);
bool isRegisterUse(LUse *use, LInstruction *ins);
bool isReusedInput(LUse *use, LInstruction *ins, bool considerCopy);
bool isRegisterUse(LUse *use, LInstruction *ins, bool considerCopy = false);
bool isRegisterDefinition(LiveInterval *interval);
bool addLiveInterval(LiveIntervalVector &intervals, uint32_t vreg,
LiveInterval *spillInterval,

View File

@ -596,6 +596,14 @@ IonBuilder::build()
if (instrumentedProfiling())
current->add(MFunctionBoundary::New(script(), MFunctionBoundary::Enter));
// Guard against over-recursion. Do this before we start unboxing, since
// this will create an OSI point that will read the incoming argument
// values, which is nice to do before their last real use, to minimize
// register/stack pressure.
MCheckOverRecursed *check = new MCheckOverRecursed;
current->add(check);
check->setResumePoint(current->entryResumePoint());
// Parameters have been checked to correspond to the typeset, now we unbox
// what we can in an infallible manner.
rewriteParameters();
@ -607,11 +615,6 @@ IonBuilder::build()
if (info().needsArgsObj() && !initArgumentsObject())
return false;
// Guard against over-recursion.
MCheckOverRecursed *check = new MCheckOverRecursed;
current->add(check);
check->setResumePoint(current->entryResumePoint());
// Prevent |this| from being DCE'd: necessary for constructors.
if (info().fun())
current->getSlot(info().thisSlot())->setGuard();
@ -6529,9 +6532,9 @@ IonBuilder::getElemTryScalarElemOfTypedObject(bool *emitted,
JS_ASSERT(objTypeReprs.allOfArrayKind());
// Must always be loading the same scalar type
if (elemTypeReprs.length() != 1)
if (!elemTypeReprs.singleton())
return true;
ScalarTypeRepresentation *elemTypeRepr = elemTypeReprs.get(0)->asScalar();
ScalarTypeRepresentation *elemTypeRepr = elemTypeReprs.getTypeRepresentation()->asScalar();
// Get the length.
size_t lenOfAll = objTypeReprs.arrayLength();
@ -6550,40 +6553,19 @@ IonBuilder::getElemTryScalarElemOfTypedObject(bool *emitted,
// Typed-object accesses usually in bounds (bail out otherwise).
index = addBoundsCheck(index, length);
// Since we passed the bounds check, it is impossible for the
// result of multiplication to overflow; so enable imul path.
const int32_t alignment = elemTypeRepr->alignment();
MMul *indexAsByteOffset = MMul::New(index, constantInt(alignment),
MIRType_Int32, MMul::Integer);
current->add(indexAsByteOffset);
// Find location within the owner object.
MDefinition *owner;
MDefinition *indexFromOwner;
if (obj->isNewDerivedTypedObject()) {
MNewDerivedTypedObject *ins = obj->toNewDerivedTypedObject();
MDefinition *ownerOffset = ins->offset();
// Typed array offsets are expressed in units of the (array)
// element alignment. The binary data uses byte units for
// offsets (such as the owner offset here).
MConstant *alignment = MConstant::New(Int32Value(elemTypeRepr->alignment()));
current->add(alignment);
MDiv *scaledOffset = MDiv::NewAsmJS(ownerOffset, alignment, MIRType_Int32);
current->add(scaledOffset);
MAdd *scaledOffsetPlusIndex = MAdd::NewAsmJS(scaledOffset, index,
MIRType_Int32);
current->add(scaledOffsetPlusIndex);
owner = ins->owner();
indexFromOwner = scaledOffsetPlusIndex;
} else {
owner = obj;
indexFromOwner = index;
}
// Load the element data.
MTypedObjectElements *elements = MTypedObjectElements::New(owner);
current->add(elements);
MDefinition *elements, *scaledOffset;
loadTypedObjectElements(obj, indexAsByteOffset, alignment, &elements, &scaledOffset);
// Load the element.
MLoadTypedArrayElement *load = MLoadTypedArrayElement::New(elements, indexFromOwner, elemTypeRepr->type());
MLoadTypedArrayElement *load = MLoadTypedArrayElement::New(elements, scaledOffset, elemTypeRepr->type());
current->add(load);
current->push(load);
@ -6613,8 +6595,7 @@ IonBuilder::getElemTryComplexElemOfTypedObject(bool *emitted,
JS_ASSERT(objTypeReprs.allOfArrayKind());
MDefinition *type = loadTypedObjectType(obj);
MInstruction *elemType = MLoadFixedSlot::New(type, JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE);
current->add(elemType);
MDefinition *elemType = typeObjectForElementFromArrayStructType(type);
// Get the length.
size_t lenOfAll = objTypeReprs.arrayLength();
@ -6644,33 +6625,14 @@ IonBuilder::getElemTryComplexElemOfTypedObject(bool *emitted,
current->add(indexAsByteOffset);
// Find location within the owner object.
MDefinition *owner;
MDefinition *indexAsByteOffsetFromOwner;
if (obj->isNewDerivedTypedObject()) {
MNewDerivedTypedObject *ins = obj->toNewDerivedTypedObject();
MDefinition *ownerOffset = ins->offset();
MAdd *offsetPlusScaledIndex = MAdd::NewAsmJS(ownerOffset,
indexAsByteOffset,
MIRType_Int32);
current->add(offsetPlusScaledIndex);
owner = ins->owner();
indexAsByteOffsetFromOwner = offsetPlusScaledIndex;
} else {
owner = obj;
indexAsByteOffsetFromOwner = indexAsByteOffset;
}
// Load the element data.
MTypedObjectElements *elements = MTypedObjectElements::New(owner);
current->add(elements);
MDefinition *owner, *ownerOffset;
loadTypedObjectData(obj, indexAsByteOffset, &owner, &ownerOffset);
// Create the derived type object.
MInstruction *derived = new MNewDerivedTypedObject(elemTypeReprs,
elemType,
owner,
indexAsByteOffsetFromOwner);
ownerOffset);
types::TemporaryTypeSet *resultTypes = bytecodeTypes(pc);
derived->setResultTypeSet(resultTypes);
@ -8228,22 +8190,19 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted,
types::TemporaryTypeSet *resultTypes)
{
// Must always be loading the same scalar type
if (fieldTypeReprs.length() != 1)
if (!fieldTypeReprs.singleton())
return true;
ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.get(0)->asScalar();
ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.getTypeRepresentation()->asScalar();
// OK!
*emitted = true;
// OK, perform the optimization
MDefinition *typedObj = current->pop();
// Find location within the owner object.
MDefinition *owner, *ownerOffset;
loadTypedObjectData(typedObj, fieldOffset, &owner, &ownerOffset);
// Load the element data.
MTypedObjectElements *elements = MTypedObjectElements::New(owner);
current->add(elements);
MDefinition *elements, *scaledOffset;
loadTypedObjectElements(typedObj, constantInt(fieldOffset),
fieldTypeRepr->alignment(),
&elements, &scaledOffset);
// Reading from an Uint32Array will result in a double for values
// that don't fit in an int32. We have to bailout if this happens
@ -8251,14 +8210,6 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted,
bool allowDouble = resultTypes->hasType(types::Type::DoubleType());
MIRType knownType = MIRTypeForTypedArrayRead(fieldTypeRepr->type(), allowDouble);
// Typed array offsets are expressed in units of the alignment,
// and the binary data API guarantees all offsets are properly
// aligned. So just do the divide.
MConstant *alignment = MConstant::New(Int32Value(fieldTypeRepr->alignment()));
current->add(alignment);
MDiv *scaledOffset = MDiv::NewAsmJS(ownerOffset, alignment, MIRType_Int32);
current->add(scaledOffset);
MLoadTypedArrayElement *load =
MLoadTypedArrayElement::New(elements, scaledOffset,
fieldTypeRepr->type());
@ -8266,6 +8217,7 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted,
load->setResultTypeSet(resultTypes);
current->add(load);
current->push(load);
*emitted = true;
return true;
}
@ -8281,7 +8233,8 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
if (fieldIndex == SIZE_MAX)
return true;
*emitted = true;
// OK, perform the optimization
MDefinition *typedObj = current->pop();
// Identify the type object for the field.
@ -8290,7 +8243,8 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
// Find location within the owner object.
MDefinition *owner, *ownerOffset;
loadTypedObjectData(typedObj, fieldOffset, &owner, &ownerOffset);
loadTypedObjectData(typedObj, constantInt(fieldOffset),
&owner, &ownerOffset);
// Create the derived type object.
MInstruction *derived = new MNewDerivedTypedObject(fieldTypeReprs,
@ -8300,6 +8254,7 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
derived->setResultTypeSet(resultTypes);
current->add(derived);
current->push(derived);
*emitted = true;
return true;
}
@ -8749,43 +8704,34 @@ IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj,
return true;
case TypeRepresentation::Scalar:
break;
return setPropTryScalarPropOfTypedObject(emitted, obj, fieldOffset,
value, fieldTypeReprs);
}
MOZ_ASSUME_UNREACHABLE("Unknown kind");
}
bool
IonBuilder::setPropTryScalarPropOfTypedObject(bool *emitted,
MDefinition *obj,
int32_t fieldOffset,
MDefinition *value,
TypeRepresentationSet fieldTypeReprs)
{
// Must always be storing the same scalar type
if (fieldTypeReprs.length() != 1)
if (!fieldTypeReprs.singleton())
return true;
ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.get(0)->asScalar();
ScalarTypeRepresentation *fieldTypeRepr =
fieldTypeReprs.getTypeRepresentation()->asScalar();
// OK!
*emitted = true;
// OK! Perform the optimization.
MTypedObjectElements *elements = MTypedObjectElements::New(obj);
current->add(elements);
// Typed array offsets are expressed in units of the alignment,
// and the binary data API guarantees all offsets are properly
// aligned.
JS_ASSERT(fieldOffset % fieldTypeRepr->alignment() == 0);
int32_t scaledFieldOffset = fieldOffset / fieldTypeRepr->alignment();
MConstant *offset = MConstant::New(Int32Value(scaledFieldOffset));
current->add(offset);
// Clamp value to [0, 255] for Uint8ClampedArray.
MDefinition *toWrite = value;
if (fieldTypeRepr->type() == ScalarTypeRepresentation::TYPE_UINT8_CLAMPED) {
toWrite = MClampToUint8::New(value);
current->add(toWrite->toInstruction());
}
MStoreTypedArrayElement *store =
MStoreTypedArrayElement::New(elements, offset, toWrite,
fieldTypeRepr->type());
current->add(store);
if (!storeScalarTypedObjectValue(obj, constantInt(fieldOffset), fieldTypeRepr, value))
return false;
current->push(value);
*emitted = true;
return true;
}
@ -9620,12 +9566,12 @@ IonBuilder::loadTypedObjectType(MDefinition *typedObj)
// into dead code).
void
IonBuilder::loadTypedObjectData(MDefinition *typedObj,
int32_t offset,
MDefinition *offset,
MDefinition **owner,
MDefinition **ownerOffset)
{
MConstant *offsetDef = MConstant::New(Int32Value(offset));
current->add(offsetDef);
JS_ASSERT(typedObj->type() == MIRType_Object);
JS_ASSERT(offset->type() == MIRType_Int32);
// Shortcircuit derived type objects, meaning the intermediate
// objects created to represent `a.b` in an expression like
@ -9636,8 +9582,7 @@ IonBuilder::loadTypedObjectData(MDefinition *typedObj,
// If we see that the
MNewDerivedTypedObject *ins = typedObj->toNewDerivedTypedObject();
MAdd *offsetAdd = MAdd::NewAsmJS(ins->offset(), offsetDef,
MIRType_Int32);
MAdd *offsetAdd = MAdd::NewAsmJS(ins->offset(), offset, MIRType_Int32);
current->add(offsetAdd);
*owner = ins->owner();
@ -9646,7 +9591,38 @@ IonBuilder::loadTypedObjectData(MDefinition *typedObj,
}
*owner = typedObj;
*ownerOffset = offsetDef;
*ownerOffset = offset;
}
// Takes as input a typed object, an offset into that typed object's
// memory, and the type repr of the data found at that offset. Returns
// the elements pointer and a scaled offset. The scaled offset is
// expressed in units of `unit`; when working with typed array MIR,
// this is typically the alignment.
void
IonBuilder::loadTypedObjectElements(MDefinition *typedObj,
MDefinition *offset,
int32_t unit,
MDefinition **ownerElements,
MDefinition **ownerScaledOffset)
{
MDefinition *owner, *ownerOffset;
loadTypedObjectData(typedObj, offset, &owner, &ownerOffset);
// Load the element data.
MTypedObjectElements *elements = MTypedObjectElements::New(owner);
current->add(elements);
// Scale to a different unit for compat with typed array MIRs.
if (unit != 1) {
MDiv *scaledOffset = MDiv::NewAsmJS(ownerOffset, constantInt(unit), MIRType_Int32);
current->add(scaledOffset);
*ownerScaledOffset = scaledOffset;
} else {
*ownerScaledOffset = ownerOffset;
}
*ownerElements = elements;
}
// Looks up the offset/type-repr-set of the field `id`, given the type
@ -9674,7 +9650,7 @@ IonBuilder::lookupTypedObjectField(MDefinition *typedObj,
fieldTypeReprs, fieldIndex))
return false;
if (fieldTypeReprs->empty())
return false;
return true;
// Field offset must be representable as signed integer.
if (offset >= size_t(INT_MAX)) {
@ -9688,6 +9664,18 @@ IonBuilder::lookupTypedObjectField(MDefinition *typedObj,
return true;
}
MDefinition *
IonBuilder::typeObjectForElementFromArrayStructType(MDefinition *typeObj)
{
MInstruction *elemType = MLoadFixedSlot::New(typeObj, JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE);
current->add(elemType);
MInstruction *unboxElemType = MUnbox::New(elemType, MIRType_Object, MUnbox::Infallible);
current->add(unboxElemType);
return unboxElemType;
}
MDefinition *
IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
size_t fieldIndex)
@ -9697,16 +9685,60 @@ IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
MInstruction *fieldTypes = MLoadFixedSlot::New(typeObj, JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES);
current->add(fieldTypes);
MInstruction *unboxFieldTypes = MUnbox::New(fieldTypes, MIRType_Object, MUnbox::Infallible);
current->add(unboxFieldTypes);
// Index into list with index of field.
MInstruction *fieldTypesElements = MElements::New(fieldTypes);
MInstruction *fieldTypesElements = MElements::New(unboxFieldTypes);
current->add(fieldTypesElements);
MConstant *fieldIndexDef = MConstant::New(Int32Value(fieldIndex));
current->add(fieldIndexDef);
MConstant *fieldIndexDef = constantInt(fieldIndex);
MInstruction *fieldType = MLoadElement::New(fieldTypesElements, fieldIndexDef, false, false);
current->add(fieldType);
return fieldType;
MInstruction *unboxFieldType = MUnbox::New(fieldType, MIRType_Object, MUnbox::Infallible);
current->add(unboxFieldType);
return unboxFieldType;
}
bool
IonBuilder::storeScalarTypedObjectValue(MDefinition *typedObj,
MDefinition *offset,
ScalarTypeRepresentation *typeRepr,
MDefinition *value)
{
// Find location within the owner object.
MDefinition *elements, *scaledOffset;
loadTypedObjectElements(typedObj, offset, typeRepr->alignment(), &elements, &scaledOffset);
// Clamp value to [0, 255] when type is Uint8Clamped
MDefinition *toWrite = value;
if (typeRepr->type() == ScalarTypeRepresentation::TYPE_UINT8_CLAMPED) {
toWrite = MClampToUint8::New(value);
current->add(toWrite->toInstruction());
}
MStoreTypedArrayElement *store =
MStoreTypedArrayElement::New(elements, scaledOffset, toWrite,
typeRepr->type());
current->add(store);
return true;
}
MConstant *
IonBuilder::constant(const Value &v)
{
MConstant *c = MConstant::New(v);
current->add(c);
return c;
}
MConstant *
IonBuilder::constantInt(int32_t i)
{
return constant(Int32Value(i));
}

View File

@ -327,6 +327,9 @@ class IonBuilder : public MIRGenerator
bool initArgumentsObject();
bool pushConstant(const Value &v);
MConstant *constant(const Value &v);
MConstant *constantInt(int32_t i);
// Add a guard which ensure that the set of type which goes through this
// generated code correspond to the observed types for the bytecode.
bool pushTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, bool needBarrier);
@ -400,6 +403,11 @@ class IonBuilder : public MIRGenerator
types::TemporaryTypeSet *objTypes);
bool setPropTryTypedObject(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value);
bool setPropTryScalarPropOfTypedObject(bool *emitted,
MDefinition *obj,
int32_t fieldOffset,
MDefinition *value,
TypeRepresentationSet fieldTypeReprs);
bool setPropTryCache(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value,
bool barrier, types::TemporaryTypeSet *objTypes);
@ -413,12 +421,22 @@ class IonBuilder : public MIRGenerator
TypeRepresentationSet *fieldTypeReprs,
size_t *fieldIndex);
MDefinition *loadTypedObjectType(MDefinition *value);
void loadTypedObjectData(MDefinition *inOwner,
int32_t inOffset,
MDefinition **outOwner,
MDefinition **outOffset);
void loadTypedObjectData(MDefinition *typedObj,
MDefinition *offset,
MDefinition **owner,
MDefinition **ownerOffset);
void loadTypedObjectElements(MDefinition *typedObj,
MDefinition *offset,
int32_t unit,
MDefinition **ownerElements,
MDefinition **ownerScaledOffset);
MDefinition *typeObjectForElementFromArrayStructType(MDefinition *typedObj);
MDefinition *typeObjectForFieldFromStructType(MDefinition *type,
size_t fieldIndex);
bool storeScalarTypedObjectValue(MDefinition *typedObj,
MDefinition *offset,
ScalarTypeRepresentation *typeRepr,
MDefinition *value);
// jsop_setelem() helpers.
bool setElemTryTyped(bool *emitted, MDefinition *object,

View File

@ -3156,12 +3156,27 @@ GetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, c
GetElementIC::canAttachTypedArrayElement(JSObject *obj, const Value &idval,
TypedOrValueRegister output)
{
if (!obj->is<TypedArrayObject>() ||
(!(idval.isInt32()) &&
!(idval.isString() && GetIndexFromString(idval.toString()) != UINT32_MAX)))
{
if (!obj->is<TypedArrayObject>())
return false;
if (!idval.isInt32() && !idval.isString())
return false;
// Don't emit a stub if the access is out of bounds. We make to make
// certain that we monitor the type coming out of the typed array when
// we generate the stub. Out of bounds accesses will hit the fallback
// path.
uint32_t index;
if (idval.isInt32()) {
index = idval.toInt32();
} else {
index = GetIndexFromString(idval.toString());
if (index == UINT32_MAX)
return false;
}
if (index >= obj->as<TypedArrayObject>().length())
return false;
// The output register is not yet specialized as a float register, the only
// way to accept float typed arrays for now is to return a Value type.

View File

@ -549,30 +549,41 @@ HandleException(ResumeFromException *rfe)
// Search each inlined frame for live iterator objects, and close
// them.
InlineFrameIterator frames(cx, &iter);
// Invalidation state will be the same for all inlined scripts in the frame.
IonScript *ionScript = nullptr;
bool invalidated = iter.checkInvalidation(&ionScript);
for (;;) {
HandleExceptionIon(cx, frames, rfe, &overrecursed);
if (rfe->kind == ResumeFromException::RESUME_BAILOUT) {
IonScript *ionScript = nullptr;
if (iter.checkInvalidation(&ionScript))
if (invalidated)
ionScript->decref(cx->runtime()->defaultFreeOp());
return;
}
JS_ASSERT(rfe->kind == ResumeFromException::RESUME_ENTRY_FRAME);
// Figure out whether SPS frame was pushed for this frame or not.
// Even if profiler is enabled, the frame being popped might have
// been entered prior to SPS being enabled, and thus not have
// a pushed SPS frame.
bool popSPSFrame = cx->runtime()->spsProfiler.enabled();
if (invalidated)
popSPSFrame = ionScript->hasSPSInstrumentation();
// When profiling, each frame popped needs a notification that
// the function has exited, so invoke the probe that a function
// is exiting.
JSScript *script = frames.script();
probes::ExitScript(cx, script, script->function(), nullptr);
probes::ExitScript(cx, script, script->function(), popSPSFrame);
if (!frames.more())
break;
++frames;
}
IonScript *ionScript = nullptr;
if (iter.checkInvalidation(&ionScript))
if (invalidated)
ionScript->decref(cx->runtime()->defaultFreeOp());
} else if (iter.isBaselineJS()) {
@ -585,7 +596,8 @@ HandleException(ResumeFromException *rfe)
// Unwind profiler pseudo-stack
JSScript *script = iter.script();
probes::ExitScript(cx, script, script->function(), iter.baselineFrame());
probes::ExitScript(cx, script, script->function(),
iter.baselineFrame()->hasPushedSPSFrame());
// After this point, any pushed SPS frame would have been popped if it needed
// to be. Unset the flag here so that if we call DebugEpilogue below,
// it doesn't try to pop the SPS frame again.

View File

@ -236,8 +236,17 @@ PrintUse(char *buf, size_t size, const LUse *use)
JS_snprintf(buf, size, "v%d:%s", use->virtualRegister(),
Registers::GetName(Registers::Code(use->registerCode())));
break;
default:
case LUse::ANY:
JS_snprintf(buf, size, "v%d:r?", use->virtualRegister());
break;
case LUse::KEEPALIVE:
JS_snprintf(buf, size, "v%d:*", use->virtualRegister());
break;
case LUse::RECOVERED_INPUT:
JS_snprintf(buf, size, "v%d:**", use->virtualRegister());
break;
default:
MOZ_ASSUME_UNREACHABLE("invalid use policy");
}
}

View File

@ -36,9 +36,7 @@ Requirement::priority() const
bool
LiveInterval::Range::contains(const Range *other) const
{
Range pre, inside, post;
intersect(other, &pre, &inside, &post);
return inside.from == other->from && inside.to == other->to;
return from <= other->from && to >= other->to;
}
void
@ -420,7 +418,7 @@ LiveRangeAllocator<VREG>::init()
// Build virtual register objects
for (size_t i = 0; i < graph.numBlocks(); i++) {
if (mir->shouldCancel("LSRA create data structures (main loop)"))
if (mir->shouldCancel("Create data structures (main loop)"))
return false;
LBlock *block = graph.getBlock(i);
@ -498,7 +496,7 @@ LiveRangeAllocator<VREG>::buildLivenessInfo()
return false;
for (size_t i = graph.numBlocks(); i > 0; i--) {
if (mir->shouldCancel("LSRA Build Liveness Info (main loop)"))
if (mir->shouldCancel("Build Liveness Info (main loop)"))
return false;
LBlock *block = graph.getBlock(i - 1);

View File

@ -51,7 +51,9 @@ class Requirement
Requirement(LAllocation fixed)
: kind_(FIXED),
allocation_(fixed)
{ }
{
JS_ASSERT(fixed == LAllocation() || !fixed.isUse());
}
// Only useful as a hint, encodes where the fixed requirement is used to
// avoid allocating a fixed register too early.
@ -59,7 +61,9 @@ class Requirement
: kind_(FIXED),
allocation_(fixed),
position_(at)
{ }
{
JS_ASSERT(fixed == LAllocation() || !fixed.isUse());
}
Requirement(uint32_t vreg, CodePosition at)
: kind_(SAME_AS_OTHER),
@ -78,6 +82,7 @@ class Requirement
uint32_t virtualRegister() const {
JS_ASSERT(allocation_.isUse());
JS_ASSERT(kind() == SAME_AS_OTHER);
return allocation_.toUse()->virtualRegister();
}
@ -618,6 +623,17 @@ class LiveRangeAllocator : public RegisterAllocator
return addMove(moves, from, to);
}
size_t findFirstNonCallSafepoint(CodePosition from) const
{
size_t i = 0;
for (; i < graph.numNonCallSafepoints(); i++) {
const LInstruction *ins = graph.getNonCallSafepoint(i);
if (from <= (forLSRA ? inputOf(ins) : outputOf(ins)))
break;
}
return i;
}
void addLiveRegistersForInterval(VirtualRegister *reg, LiveInterval *interval)
{
// Fill in the live register sets for all non-call safepoints.
@ -633,7 +649,7 @@ class LiveRangeAllocator : public RegisterAllocator
size_t i = findFirstNonCallSafepoint(start);
for (; i < graph.numNonCallSafepoints(); i++) {
LInstruction *ins = graph.getNonCallSafepoint(i);
CodePosition pos = inputOf(ins);
CodePosition pos = forLSRA ? inputOf(ins) : outputOf(ins);
// Safepoints are sorted, so we can shortcut out of this loop
// if we go out of range.

View File

@ -3673,8 +3673,15 @@ class MPowHalf
: public MUnaryInstruction,
public DoublePolicy<0>
{
bool operandIsNeverNegativeInfinity_;
bool operandIsNeverNegativeZero_;
bool operandIsNeverNaN_;
MPowHalf(MDefinition *input)
: MUnaryInstruction(input)
: MUnaryInstruction(input),
operandIsNeverNegativeInfinity_(false),
operandIsNeverNegativeZero_(false),
operandIsNeverNaN_(false)
{
setResultType(MIRType_Double);
setMovable();
@ -3688,12 +3695,22 @@ class MPowHalf
bool congruentTo(MDefinition *ins) const {
return congruentIfOperandsEqual(ins);
}
bool operandIsNeverNegativeInfinity() const {
return operandIsNeverNegativeInfinity_;
}
bool operandIsNeverNegativeZero() const {
return operandIsNeverNegativeZero_;
}
bool operandIsNeverNaN() const {
return operandIsNeverNaN_;
}
TypePolicy *typePolicy() {
return this;
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
void collectRangeInfo();
};
// Inline implementation of Math.random().

View File

@ -25,6 +25,7 @@ using mozilla::Abs;
using mozilla::CountLeadingZeroes32;
using mozilla::DoubleEqualsInt32;
using mozilla::ExponentComponent;
using mozilla::FloorLog2;
using mozilla::IsInfinite;
using mozilla::IsFinite;
using mozilla::IsNaN;
@ -284,6 +285,25 @@ SymbolicBound::print(Sprinter &sp) const
sum.print(sp);
}
// Test whether the given range's exponent tells us anything that its lower
// and upper bound values don't.
static bool
IsExponentInteresting(const Range *r)
{
// If it lacks either a lower or upper bound, the exponent is interesting.
if (!r->hasInt32Bounds())
return true;
// Otherwise if there's no fractional part, the lower and upper bounds,
// which are integers, are perfectly precise.
if (!r->canHaveFractionalPart())
return false;
// Otherwise, if the bounds are conservatively rounded across a power-of-two
// boundary, the exponent may imply a tighter range.
return FloorLog2(Max(Abs(r->lower()), Abs(r->upper()))) > r->exponent();
}
void
Range::print(Sprinter &sp) const
{
@ -320,12 +340,14 @@ Range::print(Sprinter &sp) const
}
sp.printf("]");
if (max_exponent_ == IncludesInfinityAndNaN)
sp.printf(" (U inf U NaN)", max_exponent_);
else if (max_exponent_ == IncludesInfinity)
sp.printf(" (U inf)");
else if (!hasInt32UpperBound_ || !hasInt32LowerBound_)
sp.printf(" (< pow(2, %d+1))", max_exponent_);
if (IsExponentInteresting(this)) {
if (max_exponent_ == IncludesInfinityAndNaN)
sp.printf(" (U inf U NaN)", max_exponent_);
else if (max_exponent_ == IncludesInfinity)
sp.printf(" (U inf)");
else
sp.printf(" (< pow(2, %d+1))", max_exponent_);
}
}
void
@ -390,11 +412,23 @@ Range::intersect(const Range *lhs, const Range *rhs, bool *emptyRange)
// than our newLower and newUpper. This is unusual, so we handle it here
// instead of in optimize().
//
// For example, when the floating-point range has an actual maximum value
// of 1.5, it may have a range like [0,2] and the max_exponent may be zero.
// For example, consider the range F[0,1.5]. Range analysis represents the
// lower and upper bound as integers, so we'd actually have
// F[0,2] (< pow(2, 0+1)). In this case, the exponent gives us a slightly
// more precise upper bound than the integer upper bound.
//
// When intersecting such a range with an integer range, the fractional part
// of the range is dropped, but the max exponent of 0 remains valid.
if (lhs->canHaveFractionalPart_ != rhs->canHaveFractionalPart_) {
// of the range is dropped. The max exponent of 0 remains valid, so the
// upper bound needs to be adjusted to 1.
//
// When intersecting F[0,2] (< pow(2, 0+1)) with a range like F[2,4],
// the naive intersection is I[2,2], but since the max exponent tells us
// that the value is always less than 2, the intersection is actually empty.
if (lhs->canHaveFractionalPart_ != rhs->canHaveFractionalPart_ ||
(lhs->canHaveFractionalPart_ &&
newHasInt32LowerBound && newHasInt32UpperBound &&
newLower == newUpper))
{
refineInt32BoundsByExponent(newExponent, &newLower, &newUpper);
// If we're intersecting two ranges that don't overlap, this could also
@ -2424,3 +2458,13 @@ MNot::collectRangeInfo()
{
operandIsNeverNaN_ = !Range(operand()).canBeNaN();
}
void
MPowHalf::collectRangeInfo()
{
Range inputRange(input());
operandIsNeverNegativeInfinity_ = !inputRange.canBeInfiniteOrNaN() ||
inputRange.hasInt32LowerBound();
operandIsNeverNegativeZero_ = !inputRange.canBeZero();
operandIsNeverNaN_ = !inputRange.canBeNaN();
}

View File

@ -374,11 +374,16 @@ AllocationIntegrityState::dump()
for (size_t i = 0; i < block->numPhis(); i++) {
InstructionInfo &info = blocks[blockIndex].phis[i];
LPhi *phi = block->getPhi(i);
CodePosition output(phi->id(), CodePosition::OUTPUT);
fprintf(stderr, "Phi v%u <-", info.outputs[0].virtualRegister());
// Don't print the inputOf for phi nodes, since it's never used.
fprintf(stderr, "[,%u Phi [def v%u %s] <-",
output.pos(),
info.outputs[0].virtualRegister(),
phi->getDef(0)->output()->toString());
for (size_t j = 0; j < phi->numOperands(); j++)
fprintf(stderr, " %s", info.inputs[j].toString());
fprintf(stderr, "\n");
fprintf(stderr, "]\n");
}
for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
@ -388,7 +393,10 @@ AllocationIntegrityState::dump()
CodePosition input(ins->id(), CodePosition::INPUT);
CodePosition output(ins->id(), CodePosition::OUTPUT);
fprintf(stderr, "[%u,%u %s]", input.pos(), output.pos(), ins->opName());
fprintf(stderr, "[");
if (input != CodePosition::MIN)
fprintf(stderr, "%u,%u ", input.pos(), output.pos());
fprintf(stderr, "%s]", ins->opName());
if (ins->isMoveGroup()) {
LMoveGroup *group = ins->toMoveGroup();

View File

@ -328,6 +328,8 @@ class RegisterAllocator
return CodePosition(pos, CodePosition::INPUT);
}
CodePosition inputOf(const LInstruction *ins) const {
// Phi nodes "use" their inputs before the beginning of the block.
JS_ASSERT(!ins->isPhi());
return CodePosition(ins->id(), CodePosition::INPUT);
}
@ -341,17 +343,6 @@ class RegisterAllocator
return getMoveGroupAfter(pos.ins());
}
size_t findFirstNonCallSafepoint(CodePosition from) const
{
size_t i = 0;
for (; i < graph.numNonCallSafepoints(); i++) {
const LInstruction *ins = graph.getNonCallSafepoint(i);
if (from <= inputOf(ins))
break;
}
return i;
}
CodePosition minimalDefEnd(LInstruction *ins) {
// Compute the shortest interval that captures vregs defined by ins.
// Watch for instructions that are followed by an OSI point and/or Nop.

View File

@ -162,20 +162,20 @@ TypeRepresentationSet::TypeRepresentationSet()
bool
TypeRepresentationSet::empty()
{
return length() == 0;
return length_ == 0;
}
size_t
TypeRepresentationSet::length()
bool
TypeRepresentationSet::singleton()
{
return length_;
return length_ == 1;
}
TypeRepresentation *
TypeRepresentationSet::get(size_t i)
TypeRepresentationSet::getTypeRepresentation()
{
JS_ASSERT(i < length());
return entries_[i];
JS_ASSERT(singleton());
return get(0);
}
bool

View File

@ -55,6 +55,7 @@ class TypeRepresentationSetBuilder {
class TypeRepresentationSet {
private:
friend struct TypeRepresentationSetHasher;
friend class TypeRepresentationSetBuilder;
size_t length_;
@ -62,6 +63,14 @@ class TypeRepresentationSet {
TypeRepresentationSet(size_t length, TypeRepresentation **entries);
size_t length() const {
return length_;
}
TypeRepresentation *get(uint32_t i) const {
return entries_[i];
}
public:
//////////////////////////////////////////////////////////////////////
// Constructors
@ -76,8 +85,7 @@ class TypeRepresentationSet {
// Query the set
bool empty();
size_t length();
TypeRepresentation *get(size_t i);
bool singleton();
bool allOfKind(TypeRepresentation::Kind kind);
// Returns true only when non-empty and `kind()` is
@ -99,6 +107,11 @@ class TypeRepresentationSet {
TypeRepresentation::Kind kind();
//////////////////////////////////////////////////////////////////////
// The following operations are only valid on a singleton set:
TypeRepresentation *getTypeRepresentation();
//////////////////////////////////////////////////////////////////////
// Array operations
//

View File

@ -551,19 +551,29 @@ CodeGeneratorX86Shared::visitPowHalfD(LPowHalfD *ins)
Label done, sqrt;
// Branch if not -Infinity.
masm.loadConstantDouble(NegativeInfinity(), ScratchFloatReg);
masm.branchDouble(Assembler::DoubleNotEqualOrUnordered, input, ScratchFloatReg, &sqrt);
if (!ins->mir()->operandIsNeverNegativeInfinity()) {
// Branch if not -Infinity.
masm.loadConstantDouble(NegativeInfinity(), ScratchFloatReg);
// Math.pow(-Infinity, 0.5) == Infinity.
masm.xorpd(input, input);
masm.subsd(ScratchFloatReg, input);
masm.jump(&done);
Assembler::DoubleCondition cond = Assembler::DoubleNotEqualOrUnordered;
if (ins->mir()->operandIsNeverNaN())
cond = Assembler::DoubleNotEqual;
masm.branchDouble(cond, input, ScratchFloatReg, &sqrt);
// Math.pow(-Infinity, 0.5) == Infinity.
masm.xorpd(input, input);
masm.subsd(ScratchFloatReg, input);
masm.jump(&done);
masm.bind(&sqrt);
}
if (!ins->mir()->operandIsNeverNegativeZero()) {
// Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5). Adding 0 converts any -0 to 0.
masm.xorpd(ScratchFloatReg, ScratchFloatReg);
masm.addsd(ScratchFloatReg, input);
}
// Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5). Adding 0 converts any -0 to 0.
masm.bind(&sqrt);
masm.xorpd(ScratchFloatReg, ScratchFloatReg);
masm.addsd(ScratchFloatReg, input);
masm.sqrtsd(input, input);
masm.bind(&done);

View File

@ -171,6 +171,9 @@ class LPowHalfD : public LInstructionHelper<1, 1, 0>
const LDefinition *output() {
return getDef(0);
}
MPowHalf *mir() const {
return mir_->toPowHalf();
}
};
// Takes a tableswitch with an integer to decide

View File

@ -1437,43 +1437,21 @@ js_QuoteString(ExclusiveContext *cx, JSString *str, jschar quote)
static JSObject *
GetBlockChainAtPC(JSContext *cx, JSScript *script, jsbytecode *pc)
{
jsbytecode *start = script->main();
JS_ASSERT(pc >= script->main() && pc < script->code + script->length);
JS_ASSERT(pc >= start && pc < script->code + script->length);
ptrdiff_t offset = pc - script->main();
if (!script->hasBlockScopes())
return nullptr;
BlockScopeArray *blockScopes = script->blockScopes();
JSObject *blockChain = nullptr;
for (jsbytecode *p = start; p < pc; p += GetBytecodeLength(p)) {
JSOp op = JSOp(*p);
switch (op) {
case JSOP_ENTERBLOCK:
case JSOP_ENTERLET0:
case JSOP_ENTERLET1:
case JSOP_ENTERLET2: {
JSObject *child = script->getObject(p);
JS_ASSERT_IF(blockChain, child->as<BlockObject>().stackDepth() >=
blockChain->as<BlockObject>().stackDepth());
blockChain = child;
for (uint32_t n = 0; n < blockScopes->length; n++) {
const BlockScopeNote *note = &blockScopes->vector[n];
if (note->start > offset)
break;
}
case JSOP_LEAVEBLOCK:
case JSOP_LEAVEBLOCKEXPR:
case JSOP_LEAVEFORLETIN: {
// Some LEAVEBLOCK instructions are due to early exits via
// return/break/etc. from block-scoped loops and functions. We
// should ignore these instructions, since they don't really signal
// the end of the block.
jssrcnote *sn = js_GetSrcNote(cx, script, p);
if (!(sn && SN_TYPE(sn) == SRC_HIDDEN)) {
JS_ASSERT(blockChain);
blockChain = blockChain->as<StaticBlockObject>().enclosingBlock();
JS_ASSERT_IF(blockChain, blockChain->is<BlockObject>());
}
break;
}
default:
break;
}
if (offset <= note->start + note->length)
blockChain = script->getObject(note->index);
}
return blockChain;

View File

@ -416,7 +416,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
};
uint32_t length, lineno, nslots;
uint32_t natoms, nsrcnotes, ntrynotes, nobjects, nregexps, nconsts, i;
uint32_t natoms, nsrcnotes, i;
uint32_t nconsts, nobjects, nregexps, ntrynotes, nblockscopes;
uint32_t prologLength, version;
uint32_t funLength = 0;
uint32_t nTypeSets = 0;
@ -424,7 +425,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
JSContext *cx = xdr->cx();
RootedScript script(cx);
nsrcnotes = ntrynotes = natoms = nobjects = nregexps = nconsts = 0;
natoms = nsrcnotes = 0;
nconsts = nobjects = nregexps = ntrynotes = nblockscopes = 0;
/* XDR arguments and vars. */
uint16_t nargs = 0, nvars = 0;
@ -468,6 +470,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
nregexps = script->regexps()->length;
if (script->hasTrynotes())
ntrynotes = script->trynotes()->length;
if (script->hasBlockScopes())
nblockscopes = script->blockScopes()->length;
nTypeSets = script->nTypeSets;
funLength = script->funLength;
@ -512,21 +516,20 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
if (!xdr->codeUint32(&version))
return false;
/*
* To fuse allocations, we need srcnote, atom, objects, regexp, and trynote
* counts early.
*/
// To fuse allocations, we need lengths of all embedded arrays early.
if (!xdr->codeUint32(&natoms))
return false;
if (!xdr->codeUint32(&nsrcnotes))
return false;
if (!xdr->codeUint32(&ntrynotes))
if (!xdr->codeUint32(&nconsts))
return false;
if (!xdr->codeUint32(&nobjects))
return false;
if (!xdr->codeUint32(&nregexps))
return false;
if (!xdr->codeUint32(&nconsts))
if (!xdr->codeUint32(&ntrynotes))
return false;
if (!xdr->codeUint32(&nblockscopes))
return false;
if (!xdr->codeUint32(&nTypeSets))
return false;
@ -569,8 +572,11 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
return false;
if (mode == XDR_DECODE) {
if (!JSScript::partiallyInit(cx, script, nobjects, nregexps, ntrynotes, nconsts, nTypeSets))
if (!JSScript::partiallyInit(cx, script, nconsts, nobjects, nregexps, ntrynotes,
nblockscopes, nTypeSets))
{
return false;
}
JS_ASSERT(!script->mainOffset);
script->mainOffset = prologLength;
@ -664,6 +670,14 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
return false;
}
if (nconsts) {
HeapValue *vector = script->consts()->vector;
for (i = 0; i != nconsts; ++i) {
if (!XDRScriptConst(xdr, &vector[i]))
return false;
}
}
/*
* Here looping from 0-to-length to xdr objects is essential to ensure that
* all references to enclosing blocks (via FindBlockIndex below) happen
@ -740,6 +754,7 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
*objp = tmp;
}
}
for (i = 0; i != nregexps; ++i) {
if (!XDRScriptRegExpObject(xdr, &script->regexps()->vector[i]))
return false;
@ -776,11 +791,13 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
} while (tn != tnfirst);
}
if (nconsts) {
HeapValue *vector = script->consts()->vector;
for (i = 0; i != nconsts; ++i) {
if (!XDRScriptConst(xdr, &vector[i]))
return false;
for (i = 0; i < nblockscopes; ++i) {
BlockScopeNote *note = &script->blockScopes()->vector[i];
if (!xdr->codeUint32(&note->index) ||
!xdr->codeUint32(&note->start) ||
!xdr->codeUint32(&note->length))
{
return false;
}
}
@ -1580,6 +1597,7 @@ js::FreeScriptData(JSRuntime *rt)
* ObjectArray Objects objects()
* ObjectArray Regexps regexps()
* TryNoteArray Try notes trynotes()
* BlockScopeArray Scope notes blockScopes()
*
* Then are the elements of several arrays.
* - Most of these arrays have headers listed above (if present). For each of
@ -1595,6 +1613,7 @@ js::FreeScriptData(JSRuntime *rt)
* Objects objects()->vector objects()->length
* Regexps regexps()->vector regexps()->length
* Try notes trynotes()->vector trynotes()->length
* Scope notes blockScopes()->vector blockScopes()->length
*
* IMPORTANT: This layout has two key properties.
* - It ensures that everything has sufficient alignment; in particular, the
@ -1640,6 +1659,7 @@ js::FreeScriptData(JSRuntime *rt)
JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ConstArray));
JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ObjectArray)); /* there are two of these */
JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(TryNoteArray));
JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(BlockScopeArray));
/* These assertions ensure there is no padding required between array elements. */
JS_STATIC_ASSERT(HAS_JSVAL_ALIGNMENT(HeapValue));
@ -1649,9 +1669,15 @@ JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, JSTryNote));
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(JSTryNote, uint32_t));
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(uint32_t, uint32_t));
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapValue, BlockScopeNote));
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(BlockScopeNote, BlockScopeNote));
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(JSTryNote, BlockScopeNote));
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, BlockScopeNote));
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(BlockScopeNote, uint32_t));
static inline size_t
ScriptDataSize(uint32_t nbindings, uint32_t nobjects, uint32_t nregexps,
uint32_t ntrynotes, uint32_t nconsts)
ScriptDataSize(uint32_t nbindings, uint32_t nconsts, uint32_t nobjects, uint32_t nregexps,
uint32_t ntrynotes, uint32_t nblockscopes)
{
size_t size = 0;
@ -1663,6 +1689,8 @@ ScriptDataSize(uint32_t nbindings, uint32_t nobjects, uint32_t nregexps,
size += sizeof(ObjectArray) + nregexps * sizeof(JSObject *);
if (ntrynotes != 0)
size += sizeof(TryNoteArray) + ntrynotes * sizeof(JSTryNote);
if (nblockscopes != 0)
size += sizeof(BlockScopeArray) + nblockscopes * sizeof(BlockScopeNote);
if (nbindings != 0) {
// Make sure bindings are sufficiently aligned.
@ -1736,10 +1764,12 @@ AllocScriptData(ExclusiveContext *cx, size_t size)
}
/* static */ bool
JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nobjects,
uint32_t nregexps, uint32_t ntrynotes, uint32_t nconsts, uint32_t nTypeSets)
JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nconsts,
uint32_t nobjects, uint32_t nregexps, uint32_t ntrynotes,
uint32_t nblockscopes, uint32_t nTypeSets)
{
size_t size = ScriptDataSize(script->bindings.count(), nobjects, nregexps, ntrynotes, nconsts);
size_t size = ScriptDataSize(script->bindings.count(), nconsts, nobjects, nregexps, ntrynotes,
nblockscopes);
script->data = AllocScriptData(cx, size);
if (!script->data)
return false;
@ -1765,6 +1795,10 @@ JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nobj
script->setHasArray(TRYNOTES);
cursor += sizeof(TryNoteArray);
}
if (nblockscopes != 0) {
script->setHasArray(BLOCK_SCOPES);
cursor += sizeof(BlockScopeArray);
}
if (nconsts != 0) {
JS_ASSERT(reinterpret_cast<uintptr_t>(cursor) % sizeof(jsval) == 0);
@ -1795,6 +1829,16 @@ JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nobj
cursor += vectorSize;
}
if (nblockscopes != 0) {
script->blockScopes()->length = nblockscopes;
script->blockScopes()->vector = reinterpret_cast<BlockScopeNote *>(cursor);
size_t vectorSize = nblockscopes * sizeof(script->blockScopes()->vector[0]);
#ifdef DEBUG
memset(cursor, 0, vectorSize);
#endif
cursor += vectorSize;
}
if (script->bindings.count() != 0) {
// Make sure bindings are sufficiently aligned.
cursor = reinterpret_cast<uint8_t*>
@ -1809,7 +1853,7 @@ JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nobj
/* static */ bool
JSScript::fullyInitTrivial(ExclusiveContext *cx, Handle<JSScript*> script)
{
if (!partiallyInit(cx, script, 0, 0, 0, 0, 0))
if (!partiallyInit(cx, script, 0, 0, 0, 0, 0, 0))
return false;
SharedScriptData *ssd = SharedScriptData::new_(cx, 1, 1, 0);
@ -1835,8 +1879,8 @@ JSScript::fullyInitFromEmitter(ExclusiveContext *cx, HandleScript script, Byteco
uint32_t nsrcnotes = uint32_t(bce->countFinalSourceNotes());
uint32_t natoms = bce->atomIndices->count();
if (!partiallyInit(cx, script,
bce->objectList.length, bce->regexpList.length, bce->tryNoteList.length(),
bce->constList.length(), bce->typesetCount))
bce->constList.length(), bce->objectList.length, bce->regexpList.length,
bce->tryNoteList.length(), bce->blockScopeList.length(), bce->typesetCount))
{
return false;
}
@ -1873,14 +1917,16 @@ JSScript::fullyInitFromEmitter(ExclusiveContext *cx, HandleScript script, Byteco
FunctionBox *funbox = bce->sc->isFunctionBox() ? bce->sc->asFunctionBox() : nullptr;
if (bce->tryNoteList.length() != 0)
bce->tryNoteList.finish(script->trynotes());
if (bce->constList.length() != 0)
bce->constList.finish(script->consts());
if (bce->objectList.length != 0)
bce->objectList.finish(script->objects());
if (bce->regexpList.length != 0)
bce->regexpList.finish(script->regexps());
if (bce->constList.length() != 0)
bce->constList.finish(script->consts());
if (bce->tryNoteList.length() != 0)
bce->tryNoteList.finish(script->trynotes());
if (bce->blockScopeList.length() != 0)
bce->blockScopeList.finish(script->blockScopes());
script->strict = bce->sc->strict;
script->explicitUseStrict = bce->sc->hasExplicitUseStrict();
script->bindingsAccessedDynamically = bce->sc->bindingsAccessedDynamically();
@ -2279,6 +2325,7 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
uint32_t nobjects = src->hasObjects() ? src->objects()->length : 0;
uint32_t nregexps = src->hasRegexps() ? src->regexps()->length : 0;
uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
uint32_t nblockscopes = src->hasBlockScopes() ? src->blockScopes()->length : 0;
/* Script data */
@ -2444,6 +2491,8 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
}
if (ntrynotes != 0)
dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
if (nblockscopes != 0)
dst->blockScopes()->vector = Rebase<BlockScopeNote>(dst, src, src->blockScopes()->vector);
return dst;
}

View File

@ -81,19 +81,31 @@ struct JSTryNote {
namespace js {
struct BlockScopeNote {
uint32_t index; // Index of StaticScopeObject in the object array.
uint32_t start; // Bytecode offset at which this scope starts.
uint32_t length; // Bytecode length of scope.
uint32_t padding; // Pad to 64-bit boundary.
};
struct ConstArray {
js::HeapValue *vector; /* array of indexed constant values */
uint32_t length;
};
struct ObjectArray {
js::HeapPtrObject *vector; /* array of indexed objects */
uint32_t length; /* count of indexed objects */
js::HeapPtrObject *vector; // Array of indexed objects.
uint32_t length; // Count of indexed objects.
};
struct TryNoteArray {
JSTryNote *vector; /* array of indexed try notes */
uint32_t length; /* count of indexed try notes */
JSTryNote *vector; // Array of indexed try notes.
uint32_t length; // Count of indexed try notes.
};
struct BlockScopeArray {
BlockScopeNote *vector; // Array of indexed BlockScopeNote records.
uint32_t length; // Count of indexed try notes.
};
/*
@ -552,6 +564,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
OBJECTS,
REGEXPS,
TRYNOTES,
BLOCK_SCOPES,
ARRAY_KIND_BITS
};
@ -564,7 +577,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
uint8_t generatorKindBits_:2;
// Unused padding; feel free to steal these if you need them.
uint8_t padToByte_:2;
uint8_t padToByte_:1;
// 1-bit fields.
@ -650,8 +663,9 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
// successfully creating any kind (function or other) of new JSScript.
// However, callers of fullyInitFromEmitter() do not need to do this.
static bool partiallyInit(js::ExclusiveContext *cx, JS::Handle<JSScript*> script,
uint32_t nobjects, uint32_t nregexps,
uint32_t ntrynotes, uint32_t nconsts, uint32_t nTypeSets);
uint32_t nconsts, uint32_t nobjects, uint32_t nregexps,
uint32_t ntrynotes, uint32_t nblockscopes,
uint32_t nTypeSets);
static bool fullyInitFromEmitter(js::ExclusiveContext *cx, JS::Handle<JSScript*> script,
js::frontend::BytecodeEmitter *bce);
// Initialize a no-op script.
@ -913,6 +927,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
bool hasObjects() { return hasArray(OBJECTS); }
bool hasRegexps() { return hasArray(REGEXPS); }
bool hasTrynotes() { return hasArray(TRYNOTES); }
bool hasBlockScopes() { return hasArray(BLOCK_SCOPES); }
#define OFF(fooOff, hasFoo, t) (fooOff() + (hasFoo() ? sizeof(t) : 0))
@ -920,6 +935,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
size_t objectsOffset() { return OFF(constsOffset, hasConsts, js::ConstArray); }
size_t regexpsOffset() { return OFF(objectsOffset, hasObjects, js::ObjectArray); }
size_t trynotesOffset() { return OFF(regexpsOffset, hasRegexps, js::ObjectArray); }
size_t blockScopesOffset(){ return OFF(trynotesOffset, hasTrynotes, js::TryNoteArray); }
js::ConstArray *consts() {
JS_ASSERT(hasConsts());
@ -941,6 +957,11 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
return reinterpret_cast<js::TryNoteArray *>(data + trynotesOffset());
}
js::BlockScopeArray *blockScopes() {
JS_ASSERT(hasBlockScopes());
return reinterpret_cast<js::BlockScopeArray *>(data + blockScopesOffset());
}
bool hasLoops();
js::HeapPtrAtom &getAtom(size_t index) const {

View File

@ -5796,6 +5796,10 @@ main(int argc, char **argv, char **envp)
"(default: 10)", -1)
|| !op.addBoolOption('\0', "no-fpu", "Pretend CPU does not support floating-point operations "
"to test JIT codegen (no-op on platforms other than x86).")
|| !op.addBoolOption('\0', "no-sse3", "Pretend CPU does not support SSE3 instructions and above "
"to test JIT codegen (no-op on platforms other than x86 and x64).")
|| !op.addBoolOption('\0', "no-sse4", "Pretend CPU does not support SSE4 instructions"
"to test JIT codegen (no-op on platforms other than x86 and x64).")
|| !op.addBoolOption('\0', "fuzzing-safe", "Don't expose functions that aren't safe for "
"fuzzers to call")
#ifdef DEBUG
@ -5840,6 +5844,17 @@ main(int argc, char **argv, char **envp)
if (op.getBoolOption("no-fpu"))
JSC::MacroAssembler::SetFloatingPointDisabled();
#endif
#if (defined(JS_CPU_X86) || defined(JS_CPU_X64)) && defined(JS_ION)
if (op.getBoolOption("no-sse3")) {
JSC::MacroAssembler::SetSSE3Disabled();
PropagateFlagToNestedShells("--no-sse3");
}
if (op.getBoolOption("no-sse4")) {
JSC::MacroAssembler::SetSSE4Disabled();
PropagateFlagToNestedShells("--no-sse4");
}
#endif
#endif
// Start the engine.

View File

@ -0,0 +1,61 @@
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
var BUGNUMBER = 922172;
var summary = 'redimension method';
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var T = TypedObject;
function runTests() {
var counter;
// create an array of 40 bytes with some initial data
var Bytes40 = new T.ArrayType(T.uint8, 40);
var bytes40 = new Bytes40();
for (var i = 0, counter = 0; i < 40; i++)
bytes40[i] = counter++;
// redimension to an array of 10x4 bytes, check data is unchanged
var Bytes10times4 = new T.ArrayType(new T.ArrayType(T.uint8, 4), 10);
var bytes10times4 = bytes40.redimension(Bytes10times4);
counter = 0;
for (var i = 0; i < 10; i++)
for (var j = 0; j < 4; j++)
assertEq(counter++, bytes10times4[i][j]);
// redimension to an array of 2x5x2x2, check data is unchanged
var Bytes2times5times2times2 =
new T.ArrayType(
new T.ArrayType(
new T.ArrayType(
new T.ArrayType(T.uint8, 2), 2), 5), 2);
var bytes2times5times2times2 = bytes10times4.redimension(Bytes2times5times2times2);
counter = 0;
for (var i = 0; i < 2; i++)
for (var j = 0; j < 5; j++)
for (var k = 0; k < 2; k++)
for (var l = 0; l < 2; l++)
assertEq(counter++, bytes2times5times2times2[i][j][k][l]);
// test what happens if number of elements does not match
assertThrowsInstanceOf(() => {
var Bytes10times5 = new T.ArrayType(new T.ArrayType(T.uint8, 5), 10);
bytes40.redimension(Bytes10times5);
}, TypeError, "New number of elements does not match old number of elements");
// test what happens if inner type does not match, even if size is the same
assertThrowsInstanceOf(() => {
var Words40 = new T.ArrayType(T.uint8Clamped, 40);
bytes40.redimension(Words40);
}, TypeError, "New element type is not equivalent to old element type");
reportCompare(true, true);
print("Tests complete");
}
runTests();

View File

@ -1660,7 +1660,7 @@ CASE(JSOP_RETRVAL)
if (!REGS.fp()->isYielding())
REGS.fp()->epilogue(cx);
else
probes::ExitScript(cx, script, script->function(), REGS.fp());
probes::ExitScript(cx, script, script->function(), REGS.fp()->hasPushedSPSFrame());
#if defined(JS_ION)
jit_return_pop_frame:
@ -3437,7 +3437,7 @@ DEFAULT()
if (!REGS.fp()->isYielding())
REGS.fp()->epilogue(cx);
else
probes::ExitScript(cx, script, script->function(), REGS.fp());
probes::ExitScript(cx, script, script->function(), REGS.fp()->hasPushedSPSFrame());
gc::MaybeVerifyBarriers(cx, true);

View File

@ -63,8 +63,7 @@ probes::EnterScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
}
inline bool
probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
AbstractFramePtr fp)
probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun, bool popSPSFrame)
{
bool ok = true;
@ -76,22 +75,10 @@ probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
cx->doFunctionCallback(maybeFun, script, 0);
#endif
JSRuntime *rt = cx->runtime();
/*
* Coming from IonMonkey, the fp might not be known (fp == nullptr), but
* IonMonkey will only call exitScript() when absolutely necessary, so it is
* guaranteed that fp->hasPushedSPSFrame() would have been true
*/
if ((!fp && rt->spsProfiler.enabled()) || (fp && fp.hasPushedSPSFrame()))
rt->spsProfiler.exit(cx, script, maybeFun);
return ok;
}
if (popSPSFrame)
cx->runtime()->spsProfiler.exit(cx, script, maybeFun);
inline bool
probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
StackFrame *fp)
{
return probes::ExitScript(cx, script, maybeFun, fp ? AbstractFramePtr(fp) : AbstractFramePtr());
return ok;
}
inline bool

View File

@ -69,8 +69,7 @@ bool WantNativeAddressInfo(JSContext *);
bool EnterScript(JSContext *, JSScript *, JSFunction *, StackFrame *);
/* About to leave a JS function */
bool ExitScript(JSContext *, JSScript *, JSFunction *, AbstractFramePtr);
bool ExitScript(JSContext *, JSScript *, JSFunction *, StackFrame *);
bool ExitScript(JSContext *, JSScript *, JSFunction *, bool popSPSFrame);
/* Executing a script */
bool StartExecution(JSScript *script);

View File

@ -300,7 +300,7 @@ StackFrame::epilogue(JSContext *cx)
JS_ASSERT(!hasBlockChain());
RootedScript script(cx, this->script());
probes::ExitScript(cx, script, script->function(), this);
probes::ExitScript(cx, script, script->function(), hasPushedSPSFrame());
if (isEvalFrame()) {
if (isStrictEvalFrame()) {

View File

@ -22,7 +22,7 @@ namespace js {
* and saved versions. If deserialization fails, the data should be
* invalidated if possible.
*/
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 153);
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 154);
class XDRBuffer {
public:

View File

@ -10,6 +10,7 @@
#include <stdio.h>
#include "mozilla/Util.h"
#include "mozilla/WindowsDllBlocklist.h"
#include "nsXULAppAPI.h"
#ifdef XP_MACOSX
@ -38,8 +39,8 @@ main(int argc, char** argv, char** envp)
setbuf(stdout, 0);
#endif
#ifdef XRE_HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklist();
#ifdef HAS_DLL_BLOCKLIST
DllBlocklist_Initialize();
#endif
int result = XRE_XPCShellMain(argc, argv, envp);

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<script>
function boom()
{
document.getElementsByTagName("td")[0].style.position = "absolute";
}
</script>
</head>
<body onload="boom();">
<table border=1><tbody><tr><td>X</td></tr></tbody></table>
</body>
</html>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<script>
function boom()
{
document.getElementsByTagName("td")[0].style.position = "absolute";
document.body.getClientRects(); //flush
document.getElementsByTagName("tbody")[0].style.transformStyle = "preserve-3d";
}
</script>
</head>
<body onload="boom();">
<table><tbody><tr><td></td></tr></tbody></table>
</body>
</html>

View File

@ -403,6 +403,8 @@ load 788360.html
load 793848.html
load 795646.html
skip-if(1) load 802902.html # bug 901752
load 806056-1.html
load 806056-2.html
load 813372-1.html
asserts-if(gtk2Widget,0-1) load 822865.html # bug 540078
load 833604-1.html

View File

@ -3455,6 +3455,9 @@ PresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent,
if (!targetView)
return;
targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
if (MOZ_UNLIKELY(mIsDestroying)) {
return;
}
if (aFlushOnHoverChange &&
hoverGenerationBefore != restyleManager->GetHoverGeneration()) {
// Flush so that the resulting reflow happens now so that our caller

View File

@ -600,8 +600,10 @@ protected:
}
}
virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE {
if (mPresShell)
mPresShell->ProcessSynthMouseMoveEvent(mFromScroll);
if (mPresShell) {
nsRefPtr<PresShell> shell = mPresShell;
shell->ProcessSynthMouseMoveEvent(mFromScroll);
}
}
private:
PresShell* mPresShell;

View File

@ -0,0 +1,40 @@
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml" class="reftest-wait">
<bindings xmlns="http://www.mozilla.org/xbl" xmlns:xlink="http://www.w3.org/1999/xlink">
<binding id="xbl">
<content>
<div xmlns="http://www.w3.org/1999/xhtml" style="border: 100px solid red;">
<div style="position: fixed;"/>
</div>
</content>
</binding>
</bindings>
<div style="position: absolute; -moz-column-count: 2;">
<table style="border: 100px solid green;" id="c">
<tr id="b" style="-moz-binding:url(#xbl)">
<td style="position: absolute;">
m
<span id="a">
<div style="border: 100px solid black;">
<div style="position: fixed;"/>
</div>
</span>
</td>
</tr>
</table>
</div>
<script>
var doc = document;
function doe() {
var newNode = document.createElementNS("http://www.w3.org/1999/xhtml", 'div');
newNode.innerHTML = '<div xmlns="http://www.w3.org/1999/xhtml" style="border: 100px solid black;"><div style="position: fixed;"/></div>';
document.getElementById('c').insertBefore(newNode, doc.getElementById('b'));
document.getElementById('b').removeAttribute('style');
document.documentElement.removeAttribute("class");
}
setTimeout(doe, 100);
</script>
</html>

View File

@ -0,0 +1,21 @@
<html class="reftest-wait">
<head>
<script type="text/javascript">
function boom()
{
document.execCommand("selectAll", false, null);
document.execCommand("formatBlock", false, "<h5>");
document.execCommand("justifyfull", false, null);
document.execCommand("indent", false, null);
document.execCommand("outdent", false, null);
document.getElementById("q").appendChild(document.createTextNode('v'));
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body onload="boom();" style="width: 800px; -moz-column-count: 4; column-count: 4;"><div contenteditable="true" style="height: 80px;"><div><div><hr><span> </span></div></div></div><div id="q" style="height: 80px;"><div style="float: left; height: 10px; width: 10px;"></div><div style="padding: 180px; -moz-column-count: 1; column-count: 1; clear: right;"></div></div></body>
</html>

View File

@ -0,0 +1,11 @@
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head>
<style>
span { margin: inherit; }
html, body { -moz-column-width: 1px; column-width: 1px; }
</style>
</head>
<body onload="document.getElementsByTagName('style')[0].setAttribute('foo', 'bar'); document.documentElement.removeAttribute('class');">
<span><i><spacer /><caption /></i><span><span><div /></span></span></span>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE HTML>
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Testcase for bug 654002</title>
<script>
function boom() {
var e = document.getElementById('inner');
var s = "<br>"
for (k=0;k<=14;k++) {
s += s;
}
e.innerHTML = s;
document.body.offsetHeight;
e.style.display = 'none'
document.body.offsetHeight;
}
</script>
</head>
<body onload="boom()">
<div style="width:1px;"><span><span id="inner"></span></span></div>
</body>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<script>
function expStr(s, n)
{
for (var i = 0; i < n; ++i)
s += s;
return s;
}
function boom()
{
var s = document.getElementById("s")
var t = document.createTextNode(expStr("x ", 15));
s.appendChild(t);
document.documentElement.offsetHeight;
s.removeChild(t);
}
</script>
</head>
<body onload="boom();"><div style="width: 1px"><span id="s"></span></div></body>
</html>

View File

@ -0,0 +1,28 @@
<html class="reftest-wait">
<head>
<style>
#el0 {
-moz-column-count: 3;
column-count: 3;
max-width: 13ex;
display: inline-block;
}
#el0:first-line { font-family: x; }
#el0:first-letter { float: right; }
</style>
<script>
onload = function() {
el0=document.createElement('object')
el0.setAttribute('id','el0')
document.body.appendChild(el0)
el0.appendChild(document.createTextNode(unescape('%ua000%uf400')))
el0.appendChild(document.createTextNode(unescape('%u3000')+'AA'))
el0.appendChild(document.createTextNode(''))
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,17 @@
<html class="reftest-wait">><class><address></address><children id=test1>><acronym id=test2></acronym><aside><iframe src=simple_blank.swf></iframe>
</aside><script>
setTimeout("boom()", 2000);
function boom() {
document.designMode = "on";
document.execCommand("InsertHTML", false, "<dl>")
r = document.createRange();
window.getSelection().removeAllRanges();
r.setStart(test1, 0);
r.setEnd(test2, test2.childNodes.length);
window.getSelection().addRange(r);
document.execCommand("InsertHTML", false, " ")
document.documentElement.removeAttribute("class");
}
</script>

View File

@ -136,6 +136,7 @@ load 387233-1.html
load 387233-2.html
load 387282-1.html
load 388175-1.html
load 388367-1.html
load 388709-1.html
load 389635-1.html
load 390050-1.html
@ -169,7 +170,7 @@ load 398322-1.html
load 398322-2.html
load 398332-1.html
load 398332-2.html
asserts(2) load 398332-3.html # bug 436123 and bug 457397
asserts(0-2) load 398332-3.html # bug 436123 and bug 457397
load 399407-1.xhtml
load 399412-1.html
load 399843-1.html
@ -302,6 +303,7 @@ load 463350-1.html
load 463350-2.html
load 463350-3.html
load 463741-1.html
load 463785.xhtml
load 465651-1.html
load 467137-1.html
load 467213-1.html
@ -331,6 +333,7 @@ asserts-if(!Android,1) load 479938-1.html # Bug 575011
load 480345-1.html
skip-if(Android) load 481921.html
load 489462-1.html
load 489477.html
load 489480-1.xhtml
load 493111-1.html
load 493118-1.html
@ -373,6 +376,7 @@ load 534082-1.html
load 534366-1.html
load 534366-2.html
load 536692-1.xhtml
load 537645.xhtml
load 541277-1.html
load 541277-2.html
load 541714-1.html
@ -421,6 +425,8 @@ load 646561-1.html
load 646983-1.html
load 647332-1.html
load 650499-1.html
load 654002-1.html
load 654002-2.html
load 655462-1.html
load 656130-1.html
load 656130-2.html
@ -464,6 +470,8 @@ asserts(0-200) load 767765.html # bug 407550, bug 871758, and various nscoord_MA
load 769303-1.html
load 769303-2.html
load 769120.html
load 777838.html
load 784600.html
load 786740-1.html
asserts(0-4) test-pref(font.size.inflation.emPerLine,15) load 791601.xhtml # 3 counts of bug 871327, 1 bug 367185
test-pref(font.size.inflation.minTwips,120) load 794693.html

Binary file not shown.

View File

@ -758,7 +758,6 @@ fails == 387344-1.html 387344-1-ref.html # scrolling rowgroups were removed in b
== 387876-3a.html 387876-3-ref.html
== 387876-3b.html 387876-3-ref.html
== 388026-1.html 388026-1-ref.html
== 388367-1.html about:blank
== 389074-1.html 389074-1-ref.html
== 389224-1.html 389224-1-ref.html
== 389224-2.html about:blank

View File

@ -34,30 +34,33 @@ def main():
(options, args) = parser.parse_args()
min_sdk_version = args[0]
job = subprocess.Popen(['xcode-select', '-print-path'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
out, err = job.communicate()
if job.returncode != 0:
print >>sys.stderr, out
print >>sys.stderr, err
raise Exception(('Error %d running xcode-select, you might have to run '
'|sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer| '
'if you are using Xcode 4.') % job.returncode)
# The Developer folder moved in Xcode 4.3.
xcode43_sdk_path = os.path.join(
if sys.platform == 'darwin':
job = subprocess.Popen(['xcode-select', '-print-path'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
out, err = job.communicate()
if job.returncode != 0:
print >>sys.stderr, out
print >>sys.stderr, err
raise Exception(('Error %d running xcode-select, you might have to run '
'|sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer| '
'if you are using Xcode 4.') % job.returncode)
# The Developer folder moved in Xcode 4.3.
xcode43_sdk_path = os.path.join(
out.rstrip(), 'Platforms/MacOSX.platform/Developer/SDKs')
if os.path.isdir(xcode43_sdk_path):
sdk_dir = xcode43_sdk_path
if os.path.isdir(xcode43_sdk_path):
sdk_dir = xcode43_sdk_path
else:
sdk_dir = os.path.join(out.rstrip(), 'SDKs')
sdks = [re.findall('^MacOSX(10\.\d+)\.sdk$', s) for s in os.listdir(sdk_dir)]
sdks = [s[0] for s in sdks if s] # [['10.5'], ['10.6']] => ['10.5', '10.6']
sdks = [s for s in sdks # ['10.5', '10.6'] => ['10.6']
if parse_version(s) >= parse_version(min_sdk_version)]
if not sdks:
raise Exception('No %s+ SDK found' % min_sdk_version)
best_sdk = sorted(sdks, key=parse_version)[0]
else:
sdk_dir = os.path.join(out.rstrip(), 'SDKs')
sdks = [re.findall('^MacOSX(10\.\d+)\.sdk$', s) for s in os.listdir(sdk_dir)]
sdks = [s[0] for s in sdks if s] # [['10.5'], ['10.6']] => ['10.5', '10.6']
sdks = [s for s in sdks # ['10.5', '10.6'] => ['10.6']
if parse_version(s) >= parse_version(min_sdk_version)]
if not sdks:
raise Exception('No %s+ SDK found' % min_sdk_version)
best_sdk = sorted(sdks, key=parse_version)[0]
best_sdk = ""
if options.verify and best_sdk != min_sdk_version and not options.sdk_path:
print >>sys.stderr, ''
@ -77,6 +80,4 @@ def main():
if __name__ == '__main__':
if sys.platform != 'darwin':
raise Exception("This script only runs on Mac")
print main()

View File

@ -45,7 +45,14 @@ ifneq (,$(filter -DEFAULTLIB:mozcrt,$(MOZ_GLUE_LDFLAGS)))
NO_INSTALL_IMPORT_LIBRARY = 1
endif
EXTRA_DSO_LDOPTS += $(MOZ_ZLIB_LIBS)
EXTRA_DSO_LDOPTS += \
$(MOZ_ZLIB_LIBS) \
version.lib \
$(NULL)
STL_FLAGS=
endif
ifeq (Darwin_1,$(OS_TARGET)_$(MOZ_REPLACE_MALLOC))

View File

@ -5,18 +5,15 @@
#include <windows.h>
#include <winternl.h>
#include <io.h>
#include <stdio.h>
#include <string.h>
#pragma warning( push )
#pragma warning( disable : 4275 4530 ) // See msvc-stl-wrapper.template.h
#include <map>
#pragma warning( pop )
#include "nsXULAppAPI.h"
#define MOZ_NO_MOZALLOC
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "prlog.h"
#include "nsWindowsDllInterceptor.h"
#include "mozilla/WindowsVersion.h"
@ -24,10 +21,6 @@
using namespace mozilla;
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
#define ALL_VERSIONS ((unsigned long long)-1LL)
// DLLs sometimes ship without a version number, particularly early
@ -153,7 +146,47 @@ static DllBlockInfo sWindowsDllBlocklist[] = {
// define this for very verbose dll load debug spew
#undef DEBUG_very_verbose
extern bool gInXPCOMLoadOnMainThread;
static const char kBlockedDllsParameter[] = "BlockedDllList=";
static const int kBlockedDllsParameterLen =
sizeof(kBlockedDllsParameter) - 1;
static const char kBlocklistInitFailedParameter[] = "BlocklistInitFailed=";
static const int kBlocklistInitFailedParameterLen =
sizeof(kBlocklistInitFailedParameter) - 1;
static const char kUser32BeforeBlocklistParameter[] = "User32BeforeBlocklist=";
static const int kUser32BeforeBlocklistParameterLen =
sizeof(kUser32BeforeBlocklistParameterLen) - 1;
static DWORD sThreadLoadingXPCOMModule;
static bool sBlocklistInitFailed;
static bool sUser32BeforeBlocklist;
// Duplicated from xpcom glue. Ideally this should be shared.
static void
printf_stderr(const char *fmt, ...)
{
if (IsDebuggerPresent()) {
char buf[2048];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
buf[sizeof(buf) - 1] = '\0';
va_end(args);
OutputDebugStringA(buf);
}
FILE *fp = _fdopen(_dup(2), "a");
if (!fp)
return;
va_list args;
va_start(args, fmt);
vfprintf(fp, fmt, args);
va_end(args);
fclose(fp);
}
namespace {
@ -170,7 +203,7 @@ struct RVAMap {
DWORD alignedOffset = (offset / info.dwAllocationGranularity) *
info.dwAllocationGranularity;
NS_ASSERTION(offset - alignedOffset < info.dwAllocationGranularity, "Wtf");
MOZ_ASSERT(offset - alignedOffset < info.dwAllocationGranularity, "Wtf");
mRealView = ::MapViewOfFile(map, FILE_MAP_READ, 0, alignedOffset,
sizeof(T) + (offset - alignedOffset));
@ -544,7 +577,7 @@ continue_loading:
printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer);
#endif
if (gInXPCOMLoadOnMainThread && NS_IsMainThread()) {
if (GetCurrentThreadId() == sThreadLoadingXPCOMModule) {
// Check to ensure that the DLL has ASLR.
full_fname = getFullPath(filePath, fname);
if (!full_fname) {
@ -566,31 +599,56 @@ WindowsDllInterceptor NtDllIntercept;
} // anonymous namespace
void
XRE_SetupDllBlocklist()
NS_EXPORT void
DllBlocklist_Initialize()
{
if (GetModuleHandleA("user32.dll")) {
sUser32BeforeBlocklist = true;
}
NtDllIntercept.Init("ntdll.dll");
ReentrancySentinel::InitializeStatics();
bool ok = NtDllIntercept.AddHook("LdrLoadDll", reinterpret_cast<intptr_t>(patched_LdrLoadDll), (void**) &stub_LdrLoadDll);
if (!ok) {
sBlocklistInitFailed = true;
#ifdef DEBUG
if (!ok)
printf_stderr ("LdrLoadDll hook failed, no dll blocklisting active\n");
#endif
#ifdef MOZ_CRASHREPORTER
if (!ok) {
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DllBlockList Failed\n"));
}
#endif
}
#ifdef MOZ_CRASHREPORTER
void
CrashReporter::WriteBlockedDlls(HANDLE file)
NS_EXPORT void
DllBlocklist_SetInXPCOMLoadOnMainThread(bool inXPCOMLoadOnMainThread)
{
DllBlockSet::Write(file);
if (inXPCOMLoadOnMainThread) {
MOZ_ASSERT(sThreadLoadingXPCOMModule == 0, "Only one thread should be doing this");
sThreadLoadingXPCOMModule = GetCurrentThreadId();
} else {
sThreadLoadingXPCOMModule = 0;
}
}
NS_EXPORT void
DllBlocklist_WriteNotes(HANDLE file)
{
DWORD nBytes;
WriteFile(file, kBlockedDllsParameter, kBlockedDllsParameterLen, &nBytes, nullptr);
DllBlockSet::Write(file);
WriteFile(file, "\n", 1, &nBytes, nullptr);
if (sBlocklistInitFailed) {
WriteFile(file, kBlocklistInitFailedParameter,
kBlocklistInitFailedParameterLen, &nBytes, nullptr);
WriteFile(file, "1\n", 2, &nBytes, nullptr);
}
if (sUser32BeforeBlocklist) {
WriteFile(file, kUser32BeforeBlocklistParameter,
kUser32BeforeBlocklistParameterLen, &nBytes, nullptr);
WriteFile(file, "1\n", 2, &nBytes, nullptr);
}
}
#endif

View File

@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_windowsdllblocklist_h
#define mozilla_windowsdllblocklist_h
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#include <windows.h>
#include "mozilla/GuardObjects.h"
#include "nscore.h"
#define HAS_DLL_BLOCKLIST
NS_IMPORT void DllBlocklist_Initialize();
NS_IMPORT void DllBlocklist_SetInXPCOMLoadOnMainThread(bool inXPCOMLoadOnMainThread);
NS_IMPORT void DllBlocklist_WriteNotes(HANDLE file);
class AutoSetXPCOMLoadOnMainThread
{
public:
AutoSetXPCOMLoadOnMainThread(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) {
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
DllBlocklist_SetInXPCOMLoadOnMainThread(true);
}
~AutoSetXPCOMLoadOnMainThread() {
DllBlocklist_SetInXPCOMLoadOnMainThread(false);
}
private:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
#endif // defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#endif // mozilla_windowsdllblocklist_h

View File

@ -31,6 +31,11 @@ if CONFIG['OS_TARGET'] == 'Android':
'BionicGlue.cpp',
]
if CONFIG['OS_TARGET'] == 'WINNT':
SOURCES += [
'WindowsDllBlocklist.cpp',
]
if CONFIG['MOZ_NUWA_PROCESS']:
EXPORTS.ipc += [
'Nuwa.h',
@ -42,6 +47,7 @@ if CONFIG['MOZ_NUWA_PROCESS']:
EXPORTS.mozilla += [
'arm.h',
'SSE.h',
'WindowsDllBlocklist.h',
]
if CONFIG['CPU_ARCH'].startswith('x86'):

View File

@ -83,6 +83,7 @@ using mozilla::InjectCrashRunnable;
#include "mozilla/mozalloc_oom.h"
#include "mozilla/LateWriteChecks.h"
#include "mozilla/WindowsDllBlocklist.h"
#if defined(XP_MACOSX)
CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter");
@ -222,11 +223,6 @@ static const char kIsGarbageCollectingParameter[] = "IsGarbageCollecting=";
static const int kIsGarbageCollectingParameterLen =
sizeof(kIsGarbageCollectingParameter)-1;
#ifdef XP_WIN
static const char kBlockedDllsParameter[] = "BlockedDllList=";
static const int kBlockedDllsParameterLen = sizeof(kBlockedDllsParameter) - 1;
#endif
// this holds additional data sent via the API
static Mutex* crashReporterAPILock;
static Mutex* notesFieldLock;
@ -545,9 +541,10 @@ bool MinidumpCallback(
WriteFile(hFile, isGarbageCollecting ? "1" : "0", 1, &nBytes, nullptr);
WriteFile(hFile, "\n", 1, &nBytes, nullptr);
}
WriteFile(hFile, kBlockedDllsParameter, kBlockedDllsParameterLen, &nBytes, nullptr);
WriteBlockedDlls(hFile);
WriteFile(hFile, "\n", 1, &nBytes, nullptr);
#ifdef HAS_DLL_BLOCKLIST
DllBlocklist_WriteNotes(hFile);
#endif
// Try to get some information about memory.
MEMORYSTATUSEX statex;

View File

@ -44,11 +44,6 @@ nsresult AppendAppNotesToCrashReport(const nsACString& data);
nsresult SetGarbageCollecting(bool collecting);
#ifdef XP_WIN
// Implemented by the blocklist, this method writes the blocklist annotation
void WriteBlockedDlls(HANDLE file);
#endif
nsresult SetRestartArgs(int argc, char** argv);
nsresult SetupExtraData(nsIFile* aAppDataDirectory,
const nsACString& aBuildID);

View File

@ -11,6 +11,7 @@ EXTRA_DSO_LDOPTS += \
$(MOZ_GNOMEVFS_LIBS) \
$(GLIB_LIBS) \
$(MOZ_GIO_LIBS) \
$(MOZ_DBUS_GLIB_LIBS) \
$(NULL)
LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/components/build/
@ -22,6 +23,7 @@ CXXFLAGS += \
$(MOZ_GNOMEVFS_CFLAGS) \
$(MOZ_GIO_CFLAGS) \
$(GLIB_CFLAGS) \
$(MOZ_DBUS_GLIB_CFLAGS) \
$(NULL)
ifdef MOZ_ENABLE_GTK

View File

@ -12,6 +12,8 @@
#include <gio/gio.h>
#include <gtk/gtk.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
char *
@ -377,6 +379,56 @@ nsGIOService::ShowURIForInput(const nsACString& aUri)
return rv;
}
NS_IMETHODIMP
nsGIOService::OrgFreedesktopFileManager1ShowItems(const nsACString& aPath)
{
GError* error = nullptr;
static bool org_freedesktop_FileManager1_exists = true;
if (!org_freedesktop_FileManager1_exists) {
return NS_ERROR_NOT_AVAILABLE;
}
DBusGConnection* dbusGConnection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
if (!dbusGConnection) {
if (error) {
g_printerr("Failed to open connection to session bus: %s\n", error->message);
g_error_free(error);
}
return NS_ERROR_FAILURE;
}
char *uri = g_filename_to_uri(PromiseFlatCString(aPath).get(), nullptr, nullptr);
if (uri == NULL) {
return NS_ERROR_FAILURE;
}
DBusConnection* dbusConnection = dbus_g_connection_get_connection(dbusGConnection);
// Make sure we do not exit the entire program if DBus connection get lost.
dbus_connection_set_exit_on_disconnect(dbusConnection, false);
DBusGProxy* dbusGProxy = dbus_g_proxy_new_for_name(dbusGConnection,
"org.freedesktop.FileManager1",
"/org/freedesktop/FileManager1",
"org.freedesktop.FileManager1");
const char *uris[2] = { uri, nullptr };
gboolean rv_dbus_call = dbus_g_proxy_call (dbusGProxy, "ShowItems", nullptr, G_TYPE_STRV, uris,
G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID);
g_object_unref(dbusGProxy);
dbus_g_connection_unref(dbusGConnection);
g_free(uri);
if (!rv_dbus_call) {
org_freedesktop_FileManager1_exists = false;
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
/**
* Create or find already existing application info for specified command
* and application name.

View File

@ -24,7 +24,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
EXPORTS += ['nsWindowsDllInterceptor.h']
SOURCES += [
'nsNativeAppSupportWin.cpp',
'nsWindowsDllBlocklist.cpp',
]
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
EXPORTS += ['MacQuirks.h']

View File

@ -11,24 +11,10 @@
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <fstream>
#include "platform.h"
#include "shared-libraries.h"
#if !defined(__GLIBC__) && ANDROID_VERSION < 18
/* a crapy version of getline, because it's not included in old bionics */
static ssize_t getline(char **lineptr, size_t *n, FILE *stream)
{
char *ret;
if (!*lineptr) {
*lineptr = (char*)malloc(4096);
}
ret = fgets(*lineptr, 4096, stream);
if (!ret)
return 0;
return strlen(*lineptr);
}
#endif
#if !defined(MOZ_WIDGET_GONK)
// TODO fix me with proper include
#include "nsDebug.h"
@ -91,11 +77,10 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
pid_t pid = getpid();
char path[PATH_MAX];
snprintf(path, PATH_MAX, "/proc/%d/maps", pid);
FILE *maps = fopen(path, "r");
char *line = NULL;
std::ifstream maps(path);
std::string line;
int count = 0;
size_t line_size = 0;
while (maps && getline (&line, &line_size, maps) > 0) {
while (std::getline(maps, line)) {
int ret;
//XXX: needs input sanitizing
unsigned long start;
@ -103,7 +88,7 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
char perm[6] = "";
unsigned long offset;
char name[PATH_MAX] = "";
ret = sscanf(line,
ret = sscanf(line.c_str(),
"%lx-%lx %6s %lx %*s %*x %" PATH_MAX_STRING(PATH_MAX) "s\n",
&start, &end, perm, &offset, name);
if (!strchr(perm, 'x')) {
@ -128,6 +113,5 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
}
count++;
}
free(line);
return info;
}

View File

@ -518,8 +518,10 @@ CycleCollectedJSRuntime::DescribeGCThing(bool aIsMarked, void* aThing,
}
char name[72];
uint64_t compartmentAddress = 0;
if (aTraceKind == JSTRACE_OBJECT) {
JSObject* obj = static_cast<JSObject*>(aThing);
compartmentAddress = (uint64_t)js::GetObjectCompartment(obj);
const js::Class* clasp = js::GetObjectClass(obj);
// Give the subclass a chance to do something
@ -555,7 +557,7 @@ CycleCollectedJSRuntime::DescribeGCThing(bool aIsMarked, void* aThing,
}
// Disable printing global for objects while we figure out ObjShrink fallout.
aCb.DescribeGCedNode(aIsMarked, name);
aCb.DescribeGCedNode(aIsMarked, name, compartmentAddress);
}
void

View File

@ -1115,7 +1115,7 @@ GraphWalker<Visitor>::DoWalk(nsDeque &aQueue)
struct CCGraphDescriber : public LinkedListElement<CCGraphDescriber>
{
CCGraphDescriber()
: mAddress("0x"), mToAddress("0x"), mCnt(0), mType(eUnknown) {}
: mAddress("0x"), mCnt(0), mType(eUnknown) {}
enum Type
{
@ -1129,8 +1129,8 @@ struct CCGraphDescriber : public LinkedListElement<CCGraphDescriber>
};
nsCString mAddress;
nsCString mToAddress;
nsCString mName;
nsCString mCompartmentOrToAddress;
uint32_t mCnt;
Type mType;
};
@ -1290,7 +1290,8 @@ public:
return NS_OK;
}
NS_IMETHOD NoteGCedObject(uint64_t aAddress, bool aMarked,
const char *aObjectDescription)
const char *aObjectDescription,
uint64_t aCompartmentAddress)
{
if (!mDisableLog) {
fprintf(mStream, "%p [gc%s] %s\n", (void*)aAddress,
@ -1305,6 +1306,12 @@ public:
CCGraphDescriber::eGCedObject;
d->mAddress = mCurrentAddress;
d->mName.Append(aObjectDescription);
if (aCompartmentAddress) {
d->mCompartmentOrToAddress.AssignLiteral("0x");
d->mCompartmentOrToAddress.AppendInt(aCompartmentAddress, 16);
} else {
d->mCompartmentOrToAddress.SetIsVoid(true);
}
}
return NS_OK;
}
@ -1318,7 +1325,8 @@ public:
mDescribers.insertBack(d);
d->mType = CCGraphDescriber::eEdge;
d->mAddress = mCurrentAddress;
d->mToAddress.AppendInt(aToAddress, 16);
d->mCompartmentOrToAddress.AssignLiteral("0x");
d->mCompartmentOrToAddress.AppendInt(aToAddress, 16);
d->mName.Append(aEdgeName);
}
return NS_OK;
@ -1421,11 +1429,12 @@ public:
aHandler->NoteGCedObject(d->mAddress,
d->mType ==
CCGraphDescriber::eGCMarkedObject,
d->mName);
d->mName,
d->mCompartmentOrToAddress);
break;
case CCGraphDescriber::eEdge:
aHandler->NoteEdge(d->mAddress,
d->mToAddress,
d->mCompartmentOrToAddress,
d->mName);
break;
case CCGraphDescriber::eRoot:
@ -1598,7 +1607,8 @@ public:
// nsCycleCollectionTraversalCallback methods.
NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refCount,
const char *objName);
NS_IMETHOD_(void) DescribeGCedNode(bool isMarked, const char *objName);
NS_IMETHOD_(void) DescribeGCedNode(bool isMarked, const char *objName,
uint64_t aCompartmentAddress);
NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child);
NS_IMETHOD_(void) NoteJSChild(void *child);
@ -1782,14 +1792,15 @@ GCGraphBuilder::DescribeRefCountedNode(nsrefcnt refCount, const char *objName)
}
NS_IMETHODIMP_(void)
GCGraphBuilder::DescribeGCedNode(bool isMarked, const char *objName)
GCGraphBuilder::DescribeGCedNode(bool isMarked, const char *objName,
uint64_t aCompartmentAddress)
{
uint32_t refCount = isMarked ? UINT32_MAX : 0;
mCollector->mVisitedGCed++;
if (mListener) {
mListener->NoteGCedObject((uint64_t)mCurrPi->mPointer, isMarked,
objName);
objName, aCompartmentAddress);
}
DescribeNode(refCount, objName);
@ -1923,7 +1934,8 @@ public:
NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refcount,
const char *objname) {}
NS_IMETHOD_(void) DescribeGCedNode(bool ismarked,
const char *objname) {}
const char *objname,
uint64_t aCompartmentAddress) {}
NS_IMETHOD_(void) NoteNextEdgeName(const char* name) {}
bool MayHaveChild() {
return mMayHaveChild;

Some files were not shown because too many files have changed in this diff Show More