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

View File

@ -46,6 +46,7 @@
#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
#include "mozilla/Telemetry.h" #include "mozilla/Telemetry.h"
#include "mozilla/WindowsDllBlocklist.h"
using namespace mozilla; using namespace mozilla;
@ -78,9 +79,19 @@ static void Output(const char *fmt, ... )
#if MOZ_WINCONSOLE #if MOZ_WINCONSOLE
fwprintf_s(stderr, wide_msg); fwprintf_s(stderr, wide_msg);
#else #else
MessageBoxW(nullptr, wide_msg, L"Firefox", MB_OK // Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
| MB_ICONERROR // This is a rare codepath, so we can load user32 at run-time instead.
| MB_SETFOREGROUND); 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
#endif #endif
@ -144,9 +155,6 @@ static void AttachToTestHarness()
XRE_GetFileFromPathType XRE_GetFileFromPath; XRE_GetFileFromPathType XRE_GetFileFromPath;
XRE_CreateAppDataType XRE_CreateAppData; XRE_CreateAppDataType XRE_CreateAppData;
XRE_FreeAppDataType XRE_FreeAppData; XRE_FreeAppDataType XRE_FreeAppData;
#ifdef XRE_HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklistType XRE_SetupDllBlocklist;
#endif
XRE_TelemetryAccumulateType XRE_TelemetryAccumulate; XRE_TelemetryAccumulateType XRE_TelemetryAccumulate;
XRE_StartupTimelineRecordType XRE_StartupTimelineRecord; XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
XRE_mainType XRE_main; XRE_mainType XRE_main;
@ -156,9 +164,6 @@ static const nsDynamicFunctionLoad kXULFuncs[] = {
{ "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
{ "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
{ "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
#ifdef XRE_HAS_DLL_BLOCKLIST
{ "XRE_SetupDllBlocklist", (NSFuncPtr*) &XRE_SetupDllBlocklist },
#endif
{ "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate }, { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
{ "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord }, { "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord },
{ "XRE_main", (NSFuncPtr*) &XRE_main }, { "XRE_main", (NSFuncPtr*) &XRE_main },
@ -597,6 +602,17 @@ int main(int argc, char* argv[])
nsIFile *xreDirectory; 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); nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return 255; return 255;
@ -604,10 +620,6 @@ int main(int argc, char* argv[])
XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start); XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
#ifdef XRE_HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklist();
#endif
if (gotCounters) { if (gotCounters) {
#if defined(XP_WIN) #if defined(XP_WIN)
XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS, XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS,

View File

@ -800,7 +800,7 @@ else # !WINNT || GNU_CC
endif # WINNT && !GNU_CC endif # WINNT && !GNU_CC
ifdef ENABLE_STRIP ifdef ENABLE_STRIP
$(STRIP) $@ $(STRIP) $(STRIP_FLAGS) $@
endif endif
ifdef MOZ_POST_PROGRAM_COMMAND ifdef MOZ_POST_PROGRAM_COMMAND
$(MOZ_POST_PROGRAM_COMMAND) $@ $(MOZ_POST_PROGRAM_COMMAND) $@
@ -856,7 +856,7 @@ else
endif # WINNT && !GNU_CC endif # WINNT && !GNU_CC
ifdef ENABLE_STRIP ifdef ENABLE_STRIP
$(STRIP) $@ $(STRIP) $(STRIP_FLAGS) $@
endif endif
ifdef MOZ_POST_PROGRAM_COMMAND ifdef MOZ_POST_PROGRAM_COMMAND
$(MOZ_POST_PROGRAM_COMMAND) $@ $(MOZ_POST_PROGRAM_COMMAND) $@
@ -883,7 +883,6 @@ $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(REPORT_BUILD) $(REPORT_BUILD)
$(RM) $(LIBRARY) $(RM) $(LIBRARY)
$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(SHARED_LIBRARY_LIBS) $(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(SHARED_LIBRARY_LIBS)
$(RANLIB) $@
$(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS) $(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 # When we only build a library descriptor, blow out any existing library
@ -917,14 +916,12 @@ $(IMPORT_LIBRARY): $(SHARED_LIBRARY)
$(REPORT_BUILD) $(REPORT_BUILD)
$(RM) $@ $(RM) $@
$(IMPLIB) $@ $^ $(IMPLIB) $@ $^
$(RANLIB) $@
endif # OS/2 endif # OS/2
$(HOST_LIBRARY): $(HOST_OBJS) Makefile $(HOST_LIBRARY): $(HOST_OBJS) Makefile
$(REPORT_BUILD) $(REPORT_BUILD)
$(RM) $@ $(RM) $@
$(EXPAND_LIBS_EXEC) --extract -- $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS) $(EXPAND_LIBS_EXEC) --extract -- $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
$(HOST_RANLIB) $@
ifdef HAVE_DTRACE ifdef HAVE_DTRACE
ifndef XP_MACOSX ifndef XP_MACOSX
@ -975,7 +972,7 @@ endif # WINNT && !GCC
@$(RM) foodummyfilefoo $(DELETE_AFTER_LINK) @$(RM) foodummyfilefoo $(DELETE_AFTER_LINK)
chmod +x $@ chmod +x $@
ifdef ENABLE_STRIP ifdef ENABLE_STRIP
$(STRIP) $@ $(STRIP) $(STRIP_FLAGS) $@
endif endif
ifdef MOZ_POST_DSO_LIB_COMMAND ifdef MOZ_POST_DSO_LIB_COMMAND
$(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 ========================================================
dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269) 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 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" WEBRTC_CONFIG="${WEBRTC_CONFIG} -D have_ethtool_cmd_speed_hi=0"
fi 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 \ $PYTHON ${srcdir}/media/webrtc/trunk/build/gyp_chromium \
$GYP_WEBRTC_OPTIONS \ $GYP_WEBRTC_OPTIONS \

View File

@ -15,12 +15,14 @@
SpecialPowers.pushPrefEnv( SpecialPowers.pushPrefEnv(
{'set':[["security.csp.speccompliant", true]]}, {'set':[["security.csp.speccompliant", true]]},
function() { function() {
SimpleTest.waitForExplicitFinish();
var testframe = document.getElementById('testframe'); var testframe = document.getElementById('testframe');
testframe.src = 'file_policyuri_regression_from_multipolicy.html'; testframe.src = 'file_policyuri_regression_from_multipolicy.html';
testframe.addEventListener('load', function checkInlineScriptExecuted () { testframe.addEventListener('load', function checkInlineScriptExecuted () {
is(this.contentDocument.getElementById('testdiv').innerHTML, is(this.contentDocument.getElementById('testdiv').innerHTML,
'Inline Script Executed', 'Inline Script Executed',
'Inline script should execute (it would be blocked by the policy, but the policy is report-only)'); '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)) if (!ValidateUniformSetter("Uniform1i", location_object, location))
return; return;
// Only uniform1i can take sampler settings.
if (!ValidateSamplerUniformSetter("Uniform1i", location_object, a1)) if (!ValidateSamplerUniformSetter("Uniform1i", location_object, a1))
return; return;
@ -2731,12 +2732,6 @@ WebGLContext::Uniform2i(WebGLUniformLocation *location_object, GLint a1,
if (!ValidateUniformSetter("Uniform2i", location_object, location)) if (!ValidateUniformSetter("Uniform2i", location_object, location))
return; return;
if (!ValidateSamplerUniformSetter("Uniform2i", location_object, a1) ||
!ValidateSamplerUniformSetter("Uniform2i", location_object, a2))
{
return;
}
MakeContextCurrent(); MakeContextCurrent();
gl->fUniform2i(location, a1, a2); gl->fUniform2i(location, a1, a2);
} }
@ -2749,13 +2744,6 @@ WebGLContext::Uniform3i(WebGLUniformLocation *location_object, GLint a1,
if (!ValidateUniformSetter("Uniform3i", location_object, location)) if (!ValidateUniformSetter("Uniform3i", location_object, location))
return; return;
if (!ValidateSamplerUniformSetter("Uniform3i", location_object, a1) ||
!ValidateSamplerUniformSetter("Uniform3i", location_object, a2) ||
!ValidateSamplerUniformSetter("Uniform3i", location_object, a3))
{
return;
}
MakeContextCurrent(); MakeContextCurrent();
gl->fUniform3i(location, a1, a2, a3); gl->fUniform3i(location, a1, a2, a3);
} }
@ -2768,14 +2756,6 @@ WebGLContext::Uniform4i(WebGLUniformLocation *location_object, GLint a1,
if (!ValidateUniformSetter("Uniform4i", location_object, location)) if (!ValidateUniformSetter("Uniform4i", location_object, location))
return; return;
if (!ValidateSamplerUniformSetter("Uniform4i", location_object, a1) ||
!ValidateSamplerUniformSetter("Uniform4i", location_object, a2) ||
!ValidateSamplerUniformSetter("Uniform4i", location_object, a3) ||
!ValidateSamplerUniformSetter("Uniform4i", location_object, a4))
{
return;
}
MakeContextCurrent(); MakeContextCurrent();
gl->fUniform4i(location, a1, a2, a3, a4); gl->fUniform4i(location, a1, a2, a3, a4);
} }

View File

@ -8,8 +8,8 @@
</head> </head>
<script type="application/javascript"> <script type="application/javascript">
function doTest() { function doTest() {
sendMouseEvent({type:'click'}, 'anchor');
window.parent.postMessage({type: "attempted"}, "*"); window.parent.postMessage({type: "attempted"}, "*");
sendMouseEvent({type:'click'}, 'anchor');
} }
</script> </script>
<body onload="doTest()"> <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_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_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 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 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-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_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> <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, NS_IMETHOD_(void) DescribeGCedNode(bool aIsMarked,
const char* aObjName) const char* aObjName,
uint64_t aCompartmentAddress)
{ {
} }

View File

@ -490,13 +490,17 @@ RTCPeerConnection.prototype = {
constraints = {}; constraints = {};
} }
this._mustValidateConstraints(constraints, "createOffer passed invalid 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); this._getPC().createOffer(constraints);
}, },
@ -542,12 +546,6 @@ RTCPeerConnection.prototype = {
}, },
setLocalDescription: function(desc, onSuccess, onError) { 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; let type;
switch (desc.type) { switch (desc.type) {
case "offer": case "offer":
@ -565,23 +563,19 @@ RTCPeerConnection.prototype = {
this._queueOrRun({ this._queueOrRun({
func: this._setLocalDescription, func: this._setLocalDescription,
args: [type, desc.sdp], args: [type, desc.sdp, onSuccess, onError],
wait: true, wait: true,
type: desc.type type: desc.type
}); });
}, },
_setLocalDescription: function(type, sdp) { _setLocalDescription: function(type, sdp, onSuccess, onError) {
this._onSetLocalDescriptionSuccess = onSuccess;
this._onSetLocalDescriptionFailure = onError;
this._getPC().setLocalDescription(type, sdp); this._getPC().setLocalDescription(type, sdp);
}, },
setRemoteDescription: function(desc, onSuccess, onError) { 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; let type;
switch (desc.type) { switch (desc.type) {
case "offer": case "offer":
@ -599,13 +593,15 @@ RTCPeerConnection.prototype = {
this._queueOrRun({ this._queueOrRun({
func: this._setRemoteDescription, func: this._setRemoteDescription,
args: [type, desc.sdp], args: [type, desc.sdp, onSuccess, onError],
wait: true, wait: true,
type: desc.type type: desc.type
}); });
}, },
_setRemoteDescription: function(type, sdp) { _setRemoteDescription: function(type, sdp, onSuccess, onError) {
this._onSetRemoteDescriptionSuccess = onSuccess;
this._onSetRemoteDescriptionFailure = onError;
this._getPC().setRemoteDescription(type, sdp); this._getPC().setRemoteDescription(type, sdp);
}, },

View File

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

View File

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

View File

@ -19,11 +19,6 @@
using namespace mozilla; using namespace mozilla;
#ifdef DEBUG
static bool gNoisy = false;
#endif
InsertElementTxn::InsertElementTxn() InsertElementTxn::InsertElementTxn()
: EditTxn() : EditTxn()
{ {
@ -57,23 +52,6 @@ NS_IMETHODIMP InsertElementTxn::Init(nsINode *aNode,
NS_IMETHODIMP InsertElementTxn::DoTransaction(void) 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); NS_ENSURE_TRUE(mNode && mParent, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsINode> parent = do_QueryInterface(mParent); nsCOMPtr<nsINode> parent = do_QueryInterface(mParent);
@ -115,17 +93,6 @@ NS_IMETHODIMP InsertElementTxn::DoTransaction(void)
NS_IMETHODIMP InsertElementTxn::UndoTransaction(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); NS_ENSURE_TRUE(mNode && mParent, NS_ERROR_NOT_INITIALIZED);
ErrorResult rv; ErrorResult rv;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -107,6 +107,8 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
bool aIsFirstPaint, uint64_t aFirstPaintLayersId, bool aIsFirstPaint, uint64_t aFirstPaintLayersId,
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy) nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy)
{ {
mTreeLock.AssertCurrentThreadOwns();
ContainerLayer* container = aLayer->AsContainerLayer(); ContainerLayer* container = aLayer->AsContainerLayer();
AsyncPanZoomController* apzc = nullptr; AsyncPanZoomController* apzc = nullptr;
if (container) { if (container) {
@ -315,7 +317,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
return result; return result;
} }
AsyncPanZoomController* already_AddRefed<AsyncPanZoomController>
APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent, APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
ScreenPoint aPoint) ScreenPoint aPoint)
{ {
@ -324,7 +326,7 @@ APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
// Reset the cached apz transform // Reset the cached apz transform
mCachedTransformToApzcForInputBlock = transformToApzc; mCachedTransformToApzcForInputBlock = transformToApzc;
if (!apzc) { if (!apzc) {
return nullptr; return apzc.forget();
} }
for (size_t i = 1; i < aEvent.touches.Length(); i++) { for (size_t i = 1; i < aEvent.touches.Length(); i++) {
nsIntPoint point = aEvent.touches[i]->mRefPoint; 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. // Cache apz transform so it can be used for future events in this block.
GetInputTransforms(apzc, mCachedTransformToApzcForInputBlock, transformToGecko); GetInputTransforms(apzc, mCachedTransformToApzcForInputBlock, transformToGecko);
} }
return apzc.get(); return apzc.forget();
} }
nsEventStatus nsEventStatus
@ -349,6 +351,8 @@ APZCTreeManager::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid, ScrollableLayerGuid* aOutTargetGuid,
WidgetTouchEvent* aOutEvent) WidgetTouchEvent* aOutEvent)
{ {
MOZ_ASSERT(NS_IsMainThread());
nsEventStatus ret = nsEventStatus_eIgnore; nsEventStatus ret = nsEventStatus_eIgnore;
if (!aEvent.touches.Length()) { if (!aEvent.touches.Length()) {
return ret; return ret;
@ -421,6 +425,8 @@ APZCTreeManager::ProcessMouseEvent(const WidgetMouseEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid, ScrollableLayerGuid* aOutTargetGuid,
WidgetMouseEvent* aOutEvent) WidgetMouseEvent* aOutEvent)
{ {
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y)); nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y));
if (!apzc) { if (!apzc) {
return nsEventStatus_eIgnore; return nsEventStatus_eIgnore;
@ -441,6 +447,8 @@ APZCTreeManager::ProcessEvent(const WidgetInputEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid, ScrollableLayerGuid* aOutTargetGuid,
WidgetInputEvent* aOutEvent) WidgetInputEvent* aOutEvent)
{ {
MOZ_ASSERT(NS_IsMainThread());
// Transform the refPoint // Transform the refPoint
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y)); nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y));
if (!apzc) { if (!apzc) {
@ -645,6 +653,8 @@ APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
AsyncPanZoomController* AsyncPanZoomController*
APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid) { APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid) {
mTreeLock.AssertCurrentThreadOwns();
// This walks the tree in depth-first, reverse order, so that it encounters // This walks the tree in depth-first, reverse order, so that it encounters
// APZCs front-to-back on the screen. // APZCs front-to-back on the screen.
for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) { for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
@ -663,6 +673,8 @@ APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableL
AsyncPanZoomController* AsyncPanZoomController*
APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint) 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 // 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 // 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 // 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, APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
gfx3DMatrix& aTransformToGeckoOut) 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 // 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 // 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 // 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) 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 // If either aApzc1 or aApzc2 is null, min(depth1, depth2) will be 0 and this function
// will return null. // will return null.
@ -866,7 +883,8 @@ APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomCont
// either APZC, and return the the first common ancestor encountered. // either APZC, and return the the first common ancestor encountered.
while (true) { while (true) {
if (aApzc1 == aApzc2) { if (aApzc1 == aApzc2) {
return aApzc1; ancestor = aApzc1;
break;
} }
if (depth1 <= 0) { if (depth1 <= 0) {
break; break;
@ -874,16 +892,18 @@ APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomCont
aApzc1 = aApzc1->GetParent(); aApzc1 = aApzc1->GetParent();
aApzc2 = aApzc2->GetParent(); aApzc2 = aApzc2->GetParent();
} }
return nullptr; return ancestor.forget();
} }
AsyncPanZoomController* already_AddRefed<AsyncPanZoomController>
APZCTreeManager::RootAPZCForLayersId(AsyncPanZoomController* aApzc) APZCTreeManager::RootAPZCForLayersId(AsyncPanZoomController* aApzc)
{ {
while (aApzc && !aApzc->IsRootForLayersId()) { MonitorAutoLock lock(mTreeLock);
aApzc = aApzc->GetParent(); nsRefPtr<AsyncPanZoomController> apzc = aApzc;
while (apzc && !apzc->IsRootForLayersId()) {
apzc = apzc->GetParent();
} }
return aApzc; return apzc.forget();
} }
} }

View File

@ -310,9 +310,9 @@ private:
/* Helpers */ /* Helpers */
AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid); AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint); AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint);
AsyncPanZoomController* CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2); already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
AsyncPanZoomController* RootAPZCForLayersId(AsyncPanZoomController* aApzc); already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
AsyncPanZoomController* GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent, ScreenPoint aPoint); already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent, ScreenPoint aPoint);
nsEventStatus ProcessTouchEvent(const WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetTouchEvent* aOutEvent); nsEventStatus ProcessTouchEvent(const WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetTouchEvent* aOutEvent);
nsEventStatus ProcessMouseEvent(const WidgetMouseEvent& mouseEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetMouseEvent* aOutEvent); nsEventStatus ProcessMouseEvent(const WidgetMouseEvent& mouseEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetMouseEvent* aOutEvent);
nsEventStatus ProcessEvent(const WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetInputEvent* 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 580719-1.html
load 594654-1.xhtml load 594654-1.xhtml
load 595727-1.html load 595727-1.html
load 624198.xhtml
load 633453-1.html load 633453-1.html
load 633322-1.html load 633322-1.html
load 665218.html load 665218.html

View File

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

View File

@ -1602,33 +1602,51 @@ class MutableValueOperations : public UnbarrieredMutableValueOperations<Outer>
* type-querying, value-extracting, and mutating operations. * type-querying, value-extracting, and mutating operations.
*/ */
template <> 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; typedef JS::Heap<JS::Value> Outer;
friend class ValueOperations<Outer>; friend class ValueOperations<Outer>;
friend class UnbarrieredMutableValueOperations<Outer>;
const JS::Value * extract() const { return static_cast<const Outer*>(this)->address(); } 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) { void setBarriered(const JS::Value &v) {
static_cast<JS::Heap<JS::Value> *>(this)->set(v); static_cast<JS::Heap<JS::Value> *>(this)->set(v);
} }
public: 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(JSString *str) { setBarriered(JS::StringValue(str)); }
void setString(const JS::Anchor<JSString *> &str) { setBarriered(JS::StringValue(str.get())); } void setString(const JS::Anchor<JSString *> &str) { setBarriered(JS::StringValue(str.get())); }
void setObject(JSObject &obj) { setBarriered(JS::ObjectValue(obj)); } 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) { void setObjectOrNull(JSObject *arg) {
if (arg) if (arg)
setObject(*arg); setObject(*arg);

View File

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

View File

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

View File

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

View File

@ -415,6 +415,73 @@ function TypeObjectEquivalent(otherTypeObj) {
return TYPE_TYPE_REPR(this) === TYPE_TYPE_REPR(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 // Handles
// //

View File

@ -800,7 +800,7 @@ else # !WINNT || GNU_CC
endif # WINNT && !GNU_CC endif # WINNT && !GNU_CC
ifdef ENABLE_STRIP ifdef ENABLE_STRIP
$(STRIP) $@ $(STRIP) $(STRIP_FLAGS) $@
endif endif
ifdef MOZ_POST_PROGRAM_COMMAND ifdef MOZ_POST_PROGRAM_COMMAND
$(MOZ_POST_PROGRAM_COMMAND) $@ $(MOZ_POST_PROGRAM_COMMAND) $@
@ -856,7 +856,7 @@ else
endif # WINNT && !GNU_CC endif # WINNT && !GNU_CC
ifdef ENABLE_STRIP ifdef ENABLE_STRIP
$(STRIP) $@ $(STRIP) $(STRIP_FLAGS) $@
endif endif
ifdef MOZ_POST_PROGRAM_COMMAND ifdef MOZ_POST_PROGRAM_COMMAND
$(MOZ_POST_PROGRAM_COMMAND) $@ $(MOZ_POST_PROGRAM_COMMAND) $@
@ -883,7 +883,6 @@ $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(REPORT_BUILD) $(REPORT_BUILD)
$(RM) $(LIBRARY) $(RM) $(LIBRARY)
$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(SHARED_LIBRARY_LIBS) $(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(SHARED_LIBRARY_LIBS)
$(RANLIB) $@
$(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS) $(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 # When we only build a library descriptor, blow out any existing library
@ -917,14 +916,12 @@ $(IMPORT_LIBRARY): $(SHARED_LIBRARY)
$(REPORT_BUILD) $(REPORT_BUILD)
$(RM) $@ $(RM) $@
$(IMPLIB) $@ $^ $(IMPLIB) $@ $^
$(RANLIB) $@
endif # OS/2 endif # OS/2
$(HOST_LIBRARY): $(HOST_OBJS) Makefile $(HOST_LIBRARY): $(HOST_OBJS) Makefile
$(REPORT_BUILD) $(REPORT_BUILD)
$(RM) $@ $(RM) $@
$(EXPAND_LIBS_EXEC) --extract -- $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS) $(EXPAND_LIBS_EXEC) --extract -- $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
$(HOST_RANLIB) $@
ifdef HAVE_DTRACE ifdef HAVE_DTRACE
ifndef XP_MACOSX ifndef XP_MACOSX
@ -975,7 +972,7 @@ endif # WINNT && !GCC
@$(RM) foodummyfilefoo $(DELETE_AFTER_LINK) @$(RM) foodummyfilefoo $(DELETE_AFTER_LINK)
chmod +x $@ chmod +x $@
ifdef ENABLE_STRIP ifdef ENABLE_STRIP
$(STRIP) $@ $(STRIP) $(STRIP_FLAGS) $@
endif endif
ifdef MOZ_POST_DSO_LIB_COMMAND ifdef MOZ_POST_DSO_LIB_COMMAND
$(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 ========================================================
dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269) 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 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 update; /* loop update offset (top if none) */
ptrdiff_t breaks; /* offset of last break in loop */ ptrdiff_t breaks; /* offset of last break in loop */
ptrdiff_t continues; /* offset of last continue in loop */ ptrdiff_t continues; /* offset of last continue in loop */
uint32_t blockScopeIndex; /* index of scope in BlockScopeArray */
StmtInfoBCE(ExclusiveContext *cx) : StmtInfoBase(cx) {} StmtInfoBCE(ExclusiveContext *cx) : StmtInfoBase(cx) {}
@ -100,10 +101,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
atomIndices(sc->context), atomIndices(sc->context),
firstLine(lineNum), firstLine(lineNum),
stackDepth(0), maxStackDepth(0), stackDepth(0), maxStackDepth(0),
tryNoteList(sc->context),
arrayCompDepth(0), arrayCompDepth(0),
emitLevel(0), emitLevel(0),
constList(sc->context), constList(sc->context),
tryNoteList(sc->context),
blockScopeList(sc->context),
typesetCount(0), typesetCount(0),
hasSingletons(false), hasSingletons(false),
emittingForInit(false), emittingForInit(false),
@ -686,13 +688,23 @@ EnclosingStaticScope(BytecodeEmitter *bce)
} }
// Push a block scope statement and link blockObj into bce->blockChain. // Push a block scope statement and link blockObj into bce->blockChain.
static void static bool
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StaticBlockObject &blockObj, PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
ptrdiff_t top) ptrdiff_t top)
{ {
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
PushStatementBCE(bce, stmt, STMT_BLOCK, top); 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)); blockObj.initEnclosingStaticScope(EnclosingStaticScope(bce));
FinishPushBlockScope(bce, stmt, blockObj); FinishPushBlockScope(bce, stmt, blockObj);
return true;
} }
// Patches |breaks| and |continues| unless the top statement info record // Patches |breaks| and |continues| unless the top statement info record
@ -707,6 +719,10 @@ PopStatementBCE(ExclusiveContext *cx, BytecodeEmitter *bce)
{ {
return false; return false;
} }
if (stmt->isBlockScope)
bce->blockScopeList.recordEnd(stmt->blockScopeIndex, bce->offset());
FinishPopStatement(bce); FinishPopStatement(bce);
return true; return true;
} }
@ -770,10 +786,17 @@ EmitAtomOp(ExclusiveContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
} }
static bool 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); 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 static bool
@ -1061,7 +1084,15 @@ static bool
EmitEnterBlock(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op) EmitEnterBlock(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
{ {
JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE)); 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; return false;
Rooted<StaticBlockObject*> blockObj(cx, &pn->pn_objbox->object->as<StaticBlockObject>()); Rooted<StaticBlockObject*> blockObj(cx, &pn->pn_objbox->object->as<StaticBlockObject>());
@ -2305,7 +2336,8 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return false; return false;
if (pn2->isKind(PNK_LEXICALSCOPE)) { 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; stmtInfo.type = STMT_SWITCH;
if (!EmitEnterBlock(cx, bce, pn2, JSOP_ENTERLET1)) if (!EmitEnterBlock(cx, bce, pn2, JSOP_ENTERLET1))
return false; return false;
@ -4193,7 +4225,8 @@ EmitLet(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
} }
StmtInfoBCE stmtInfo(cx); 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(); DebugOnly<ptrdiff_t> bodyBegin = bce->offset();
if (!EmitEnterBlock(cx, bce, letBody, JSOP_ENTERLET0)) if (!EmitEnterBlock(cx, bce, letBody, JSOP_ENTERLET0))
@ -4226,7 +4259,8 @@ EmitLexicalScope(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
ObjectBox *objbox = pn->pn_objbox; ObjectBox *objbox = pn->pn_objbox;
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>(); StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
size_t slots = blockObj.slotCount(); 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)) if (!EmitEnterBlock(cx, bce, pn, JSOP_ENTERBLOCK))
return false; 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. // Enter the block before the loop body, after evaluating the obj.
StmtInfoBCE letStmt(cx); StmtInfoBCE letStmt(cx);
if (letDecl) { if (letDecl) {
PushBlockScopeBCE(bce, &letStmt, *blockObj, bce->offset()); if (!PushBlockScopeBCE(bce, &letStmt, pn1->pn_objbox, bce->offset()))
return false;
letStmt.isForLetBlock = true; letStmt.isForLetBlock = true;
if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET2)) if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET2))
return false; 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. */ /* Enter the block before the loop body, after evaluating the obj. */
StmtInfoBCE letStmt(cx); StmtInfoBCE letStmt(cx);
if (letDecl) { if (letDecl) {
PushBlockScopeBCE(bce, &letStmt, *blockObj, bce->offset()); if (!PushBlockScopeBCE(bce, &letStmt, pn1->pn_objbox, bce->offset()))
return false;
letStmt.isForLetBlock = true; letStmt.isForLetBlock = true;
if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1)) if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1))
return false; return false;
@ -6775,25 +6811,8 @@ frontend::FinishTakingSrcNotes(ExclusiveContext *cx, BytecodeEmitter *bce, jssrc
return true; 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 void
CGTryNoteList::finish(TryNoteArray *array) CGConstList::finish(ConstArray *array)
{ {
JS_ASSERT(length() == array->length); JS_ASSERT(length() == array->length);
@ -6878,8 +6897,56 @@ CGObjectList::finish(ObjectArray *array)
JS_ASSERT(cursor == array->vector); 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 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); JS_ASSERT(length() == array->length);

View File

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

View File

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

View File

@ -1,6 +1,18 @@
(function() { (function() {
"use asm" "use asm";
function f() { 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 = ParallelArray([1942], function() {})
x + watch.call(x, "length", (function() {})); x + watch.call(x, "length", (function() {}));

View File

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

View File

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

View File

@ -596,6 +596,14 @@ IonBuilder::build()
if (instrumentedProfiling()) if (instrumentedProfiling())
current->add(MFunctionBoundary::New(script(), MFunctionBoundary::Enter)); 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 // Parameters have been checked to correspond to the typeset, now we unbox
// what we can in an infallible manner. // what we can in an infallible manner.
rewriteParameters(); rewriteParameters();
@ -607,11 +615,6 @@ IonBuilder::build()
if (info().needsArgsObj() && !initArgumentsObject()) if (info().needsArgsObj() && !initArgumentsObject())
return false; 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. // Prevent |this| from being DCE'd: necessary for constructors.
if (info().fun()) if (info().fun())
current->getSlot(info().thisSlot())->setGuard(); current->getSlot(info().thisSlot())->setGuard();
@ -6529,9 +6532,9 @@ IonBuilder::getElemTryScalarElemOfTypedObject(bool *emitted,
JS_ASSERT(objTypeReprs.allOfArrayKind()); JS_ASSERT(objTypeReprs.allOfArrayKind());
// Must always be loading the same scalar type // Must always be loading the same scalar type
if (elemTypeReprs.length() != 1) if (!elemTypeReprs.singleton())
return true; return true;
ScalarTypeRepresentation *elemTypeRepr = elemTypeReprs.get(0)->asScalar(); ScalarTypeRepresentation *elemTypeRepr = elemTypeReprs.getTypeRepresentation()->asScalar();
// Get the length. // Get the length.
size_t lenOfAll = objTypeReprs.arrayLength(); size_t lenOfAll = objTypeReprs.arrayLength();
@ -6550,40 +6553,19 @@ IonBuilder::getElemTryScalarElemOfTypedObject(bool *emitted,
// Typed-object accesses usually in bounds (bail out otherwise). // Typed-object accesses usually in bounds (bail out otherwise).
index = addBoundsCheck(index, length); 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. // Find location within the owner object.
MDefinition *owner; MDefinition *elements, *scaledOffset;
MDefinition *indexFromOwner; loadTypedObjectElements(obj, indexAsByteOffset, alignment, &elements, &scaledOffset);
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);
// Load the element. // Load the element.
MLoadTypedArrayElement *load = MLoadTypedArrayElement::New(elements, indexFromOwner, elemTypeRepr->type()); MLoadTypedArrayElement *load = MLoadTypedArrayElement::New(elements, scaledOffset, elemTypeRepr->type());
current->add(load); current->add(load);
current->push(load); current->push(load);
@ -6613,8 +6595,7 @@ IonBuilder::getElemTryComplexElemOfTypedObject(bool *emitted,
JS_ASSERT(objTypeReprs.allOfArrayKind()); JS_ASSERT(objTypeReprs.allOfArrayKind());
MDefinition *type = loadTypedObjectType(obj); MDefinition *type = loadTypedObjectType(obj);
MInstruction *elemType = MLoadFixedSlot::New(type, JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE); MDefinition *elemType = typeObjectForElementFromArrayStructType(type);
current->add(elemType);
// Get the length. // Get the length.
size_t lenOfAll = objTypeReprs.arrayLength(); size_t lenOfAll = objTypeReprs.arrayLength();
@ -6644,33 +6625,14 @@ IonBuilder::getElemTryComplexElemOfTypedObject(bool *emitted,
current->add(indexAsByteOffset); current->add(indexAsByteOffset);
// Find location within the owner object. // Find location within the owner object.
MDefinition *owner; MDefinition *owner, *ownerOffset;
MDefinition *indexAsByteOffsetFromOwner; loadTypedObjectData(obj, indexAsByteOffset, &owner, &ownerOffset);
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);
// Create the derived type object. // Create the derived type object.
MInstruction *derived = new MNewDerivedTypedObject(elemTypeReprs, MInstruction *derived = new MNewDerivedTypedObject(elemTypeReprs,
elemType, elemType,
owner, owner,
indexAsByteOffsetFromOwner); ownerOffset);
types::TemporaryTypeSet *resultTypes = bytecodeTypes(pc); types::TemporaryTypeSet *resultTypes = bytecodeTypes(pc);
derived->setResultTypeSet(resultTypes); derived->setResultTypeSet(resultTypes);
@ -8228,22 +8190,19 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted,
types::TemporaryTypeSet *resultTypes) types::TemporaryTypeSet *resultTypes)
{ {
// Must always be loading the same scalar type // Must always be loading the same scalar type
if (fieldTypeReprs.length() != 1) if (!fieldTypeReprs.singleton())
return true; return true;
ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.get(0)->asScalar(); ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.getTypeRepresentation()->asScalar();
// OK! // OK, perform the optimization
*emitted = true;
MDefinition *typedObj = current->pop(); MDefinition *typedObj = current->pop();
// Find location within the owner object. // Find location within the owner object.
MDefinition *owner, *ownerOffset; MDefinition *elements, *scaledOffset;
loadTypedObjectData(typedObj, fieldOffset, &owner, &ownerOffset); loadTypedObjectElements(typedObj, constantInt(fieldOffset),
fieldTypeRepr->alignment(),
// Load the element data. &elements, &scaledOffset);
MTypedObjectElements *elements = MTypedObjectElements::New(owner);
current->add(elements);
// Reading from an Uint32Array will result in a double for values // 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 // 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()); bool allowDouble = resultTypes->hasType(types::Type::DoubleType());
MIRType knownType = MIRTypeForTypedArrayRead(fieldTypeRepr->type(), allowDouble); 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 *load =
MLoadTypedArrayElement::New(elements, scaledOffset, MLoadTypedArrayElement::New(elements, scaledOffset,
fieldTypeRepr->type()); fieldTypeRepr->type());
@ -8266,6 +8217,7 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted,
load->setResultTypeSet(resultTypes); load->setResultTypeSet(resultTypes);
current->add(load); current->add(load);
current->push(load); current->push(load);
*emitted = true;
return true; return true;
} }
@ -8281,7 +8233,8 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
if (fieldIndex == SIZE_MAX) if (fieldIndex == SIZE_MAX)
return true; return true;
*emitted = true; // OK, perform the optimization
MDefinition *typedObj = current->pop(); MDefinition *typedObj = current->pop();
// Identify the type object for the field. // Identify the type object for the field.
@ -8290,7 +8243,8 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
// Find location within the owner object. // Find location within the owner object.
MDefinition *owner, *ownerOffset; MDefinition *owner, *ownerOffset;
loadTypedObjectData(typedObj, fieldOffset, &owner, &ownerOffset); loadTypedObjectData(typedObj, constantInt(fieldOffset),
&owner, &ownerOffset);
// Create the derived type object. // Create the derived type object.
MInstruction *derived = new MNewDerivedTypedObject(fieldTypeReprs, MInstruction *derived = new MNewDerivedTypedObject(fieldTypeReprs,
@ -8300,6 +8254,7 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
derived->setResultTypeSet(resultTypes); derived->setResultTypeSet(resultTypes);
current->add(derived); current->add(derived);
current->push(derived); current->push(derived);
*emitted = true;
return true; return true;
} }
@ -8749,43 +8704,34 @@ IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj,
return true; return true;
case TypeRepresentation::Scalar: 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 // Must always be storing the same scalar type
if (fieldTypeReprs.length() != 1) if (!fieldTypeReprs.singleton())
return true; return true;
ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.get(0)->asScalar(); ScalarTypeRepresentation *fieldTypeRepr =
fieldTypeReprs.getTypeRepresentation()->asScalar();
// OK! // OK! Perform the optimization.
*emitted = true;
MTypedObjectElements *elements = MTypedObjectElements::New(obj); if (!storeScalarTypedObjectValue(obj, constantInt(fieldOffset), fieldTypeRepr, value))
current->add(elements); return false;
// 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);
current->push(value); current->push(value);
*emitted = true;
return true; return true;
} }
@ -9620,12 +9566,12 @@ IonBuilder::loadTypedObjectType(MDefinition *typedObj)
// into dead code). // into dead code).
void void
IonBuilder::loadTypedObjectData(MDefinition *typedObj, IonBuilder::loadTypedObjectData(MDefinition *typedObj,
int32_t offset, MDefinition *offset,
MDefinition **owner, MDefinition **owner,
MDefinition **ownerOffset) MDefinition **ownerOffset)
{ {
MConstant *offsetDef = MConstant::New(Int32Value(offset)); JS_ASSERT(typedObj->type() == MIRType_Object);
current->add(offsetDef); JS_ASSERT(offset->type() == MIRType_Int32);
// Shortcircuit derived type objects, meaning the intermediate // Shortcircuit derived type objects, meaning the intermediate
// objects created to represent `a.b` in an expression like // objects created to represent `a.b` in an expression like
@ -9636,8 +9582,7 @@ IonBuilder::loadTypedObjectData(MDefinition *typedObj,
// If we see that the // If we see that the
MNewDerivedTypedObject *ins = typedObj->toNewDerivedTypedObject(); MNewDerivedTypedObject *ins = typedObj->toNewDerivedTypedObject();
MAdd *offsetAdd = MAdd::NewAsmJS(ins->offset(), offsetDef, MAdd *offsetAdd = MAdd::NewAsmJS(ins->offset(), offset, MIRType_Int32);
MIRType_Int32);
current->add(offsetAdd); current->add(offsetAdd);
*owner = ins->owner(); *owner = ins->owner();
@ -9646,7 +9591,38 @@ IonBuilder::loadTypedObjectData(MDefinition *typedObj,
} }
*owner = 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 // Looks up the offset/type-repr-set of the field `id`, given the type
@ -9674,7 +9650,7 @@ IonBuilder::lookupTypedObjectField(MDefinition *typedObj,
fieldTypeReprs, fieldIndex)) fieldTypeReprs, fieldIndex))
return false; return false;
if (fieldTypeReprs->empty()) if (fieldTypeReprs->empty())
return false; return true;
// Field offset must be representable as signed integer. // Field offset must be representable as signed integer.
if (offset >= size_t(INT_MAX)) { if (offset >= size_t(INT_MAX)) {
@ -9688,6 +9664,18 @@ IonBuilder::lookupTypedObjectField(MDefinition *typedObj,
return true; 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 * MDefinition *
IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj, IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
size_t fieldIndex) size_t fieldIndex)
@ -9697,16 +9685,60 @@ IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
MInstruction *fieldTypes = MLoadFixedSlot::New(typeObj, JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES); MInstruction *fieldTypes = MLoadFixedSlot::New(typeObj, JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES);
current->add(fieldTypes); current->add(fieldTypes);
MInstruction *unboxFieldTypes = MUnbox::New(fieldTypes, MIRType_Object, MUnbox::Infallible);
current->add(unboxFieldTypes);
// Index into list with index of field. // Index into list with index of field.
MInstruction *fieldTypesElements = MElements::New(fieldTypes); MInstruction *fieldTypesElements = MElements::New(unboxFieldTypes);
current->add(fieldTypesElements); current->add(fieldTypesElements);
MConstant *fieldIndexDef = MConstant::New(Int32Value(fieldIndex)); MConstant *fieldIndexDef = constantInt(fieldIndex);
current->add(fieldIndexDef);
MInstruction *fieldType = MLoadElement::New(fieldTypesElements, fieldIndexDef, false, false); MInstruction *fieldType = MLoadElement::New(fieldTypesElements, fieldIndexDef, false, false);
current->add(fieldType); 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 initArgumentsObject();
bool pushConstant(const Value &v); 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 // Add a guard which ensure that the set of type which goes through this
// generated code correspond to the observed types for the bytecode. // generated code correspond to the observed types for the bytecode.
bool pushTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, bool needBarrier); bool pushTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, bool needBarrier);
@ -400,6 +403,11 @@ class IonBuilder : public MIRGenerator
types::TemporaryTypeSet *objTypes); types::TemporaryTypeSet *objTypes);
bool setPropTryTypedObject(bool *emitted, MDefinition *obj, bool setPropTryTypedObject(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value); PropertyName *name, MDefinition *value);
bool setPropTryScalarPropOfTypedObject(bool *emitted,
MDefinition *obj,
int32_t fieldOffset,
MDefinition *value,
TypeRepresentationSet fieldTypeReprs);
bool setPropTryCache(bool *emitted, MDefinition *obj, bool setPropTryCache(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value, PropertyName *name, MDefinition *value,
bool barrier, types::TemporaryTypeSet *objTypes); bool barrier, types::TemporaryTypeSet *objTypes);
@ -413,12 +421,22 @@ class IonBuilder : public MIRGenerator
TypeRepresentationSet *fieldTypeReprs, TypeRepresentationSet *fieldTypeReprs,
size_t *fieldIndex); size_t *fieldIndex);
MDefinition *loadTypedObjectType(MDefinition *value); MDefinition *loadTypedObjectType(MDefinition *value);
void loadTypedObjectData(MDefinition *inOwner, void loadTypedObjectData(MDefinition *typedObj,
int32_t inOffset, MDefinition *offset,
MDefinition **outOwner, MDefinition **owner,
MDefinition **outOffset); MDefinition **ownerOffset);
void loadTypedObjectElements(MDefinition *typedObj,
MDefinition *offset,
int32_t unit,
MDefinition **ownerElements,
MDefinition **ownerScaledOffset);
MDefinition *typeObjectForElementFromArrayStructType(MDefinition *typedObj);
MDefinition *typeObjectForFieldFromStructType(MDefinition *type, MDefinition *typeObjectForFieldFromStructType(MDefinition *type,
size_t fieldIndex); size_t fieldIndex);
bool storeScalarTypedObjectValue(MDefinition *typedObj,
MDefinition *offset,
ScalarTypeRepresentation *typeRepr,
MDefinition *value);
// jsop_setelem() helpers. // jsop_setelem() helpers.
bool setElemTryTyped(bool *emitted, MDefinition *object, 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, GetElementIC::canAttachTypedArrayElement(JSObject *obj, const Value &idval,
TypedOrValueRegister output) TypedOrValueRegister output)
{ {
if (!obj->is<TypedArrayObject>() || if (!obj->is<TypedArrayObject>())
(!(idval.isInt32()) &&
!(idval.isString() && GetIndexFromString(idval.toString()) != UINT32_MAX)))
{
return false; 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 // 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. // 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 // Search each inlined frame for live iterator objects, and close
// them. // them.
InlineFrameIterator frames(cx, &iter); 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 (;;) { for (;;) {
HandleExceptionIon(cx, frames, rfe, &overrecursed); HandleExceptionIon(cx, frames, rfe, &overrecursed);
if (rfe->kind == ResumeFromException::RESUME_BAILOUT) { if (rfe->kind == ResumeFromException::RESUME_BAILOUT) {
IonScript *ionScript = nullptr; if (invalidated)
if (iter.checkInvalidation(&ionScript))
ionScript->decref(cx->runtime()->defaultFreeOp()); ionScript->decref(cx->runtime()->defaultFreeOp());
return; return;
} }
JS_ASSERT(rfe->kind == ResumeFromException::RESUME_ENTRY_FRAME); 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 // When profiling, each frame popped needs a notification that
// the function has exited, so invoke the probe that a function // the function has exited, so invoke the probe that a function
// is exiting. // is exiting.
JSScript *script = frames.script(); JSScript *script = frames.script();
probes::ExitScript(cx, script, script->function(), nullptr); probes::ExitScript(cx, script, script->function(), popSPSFrame);
if (!frames.more()) if (!frames.more())
break; break;
++frames; ++frames;
} }
IonScript *ionScript = nullptr; if (invalidated)
if (iter.checkInvalidation(&ionScript))
ionScript->decref(cx->runtime()->defaultFreeOp()); ionScript->decref(cx->runtime()->defaultFreeOp());
} else if (iter.isBaselineJS()) { } else if (iter.isBaselineJS()) {
@ -585,7 +596,8 @@ HandleException(ResumeFromException *rfe)
// Unwind profiler pseudo-stack // Unwind profiler pseudo-stack
JSScript *script = iter.script(); 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 // 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, // to be. Unset the flag here so that if we call DebugEpilogue below,
// it doesn't try to pop the SPS frame again. // 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(), JS_snprintf(buf, size, "v%d:%s", use->virtualRegister(),
Registers::GetName(Registers::Code(use->registerCode()))); Registers::GetName(Registers::Code(use->registerCode())));
break; 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()); 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 bool
LiveInterval::Range::contains(const Range *other) const LiveInterval::Range::contains(const Range *other) const
{ {
Range pre, inside, post; return from <= other->from && to >= other->to;
intersect(other, &pre, &inside, &post);
return inside.from == other->from && inside.to == other->to;
} }
void void
@ -420,7 +418,7 @@ LiveRangeAllocator<VREG>::init()
// Build virtual register objects // Build virtual register objects
for (size_t i = 0; i < graph.numBlocks(); i++) { 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; return false;
LBlock *block = graph.getBlock(i); LBlock *block = graph.getBlock(i);
@ -498,7 +496,7 @@ LiveRangeAllocator<VREG>::buildLivenessInfo()
return false; return false;
for (size_t i = graph.numBlocks(); i > 0; i--) { 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; return false;
LBlock *block = graph.getBlock(i - 1); LBlock *block = graph.getBlock(i - 1);

View File

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

View File

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

View File

@ -25,6 +25,7 @@ using mozilla::Abs;
using mozilla::CountLeadingZeroes32; using mozilla::CountLeadingZeroes32;
using mozilla::DoubleEqualsInt32; using mozilla::DoubleEqualsInt32;
using mozilla::ExponentComponent; using mozilla::ExponentComponent;
using mozilla::FloorLog2;
using mozilla::IsInfinite; using mozilla::IsInfinite;
using mozilla::IsFinite; using mozilla::IsFinite;
using mozilla::IsNaN; using mozilla::IsNaN;
@ -284,6 +285,25 @@ SymbolicBound::print(Sprinter &sp) const
sum.print(sp); 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 void
Range::print(Sprinter &sp) const Range::print(Sprinter &sp) const
{ {
@ -320,12 +340,14 @@ Range::print(Sprinter &sp) const
} }
sp.printf("]"); sp.printf("]");
if (max_exponent_ == IncludesInfinityAndNaN) if (IsExponentInteresting(this)) {
sp.printf(" (U inf U NaN)", max_exponent_); if (max_exponent_ == IncludesInfinityAndNaN)
else if (max_exponent_ == IncludesInfinity) sp.printf(" (U inf U NaN)", max_exponent_);
sp.printf(" (U inf)"); else if (max_exponent_ == IncludesInfinity)
else if (!hasInt32UpperBound_ || !hasInt32LowerBound_) sp.printf(" (U inf)");
sp.printf(" (< pow(2, %d+1))", max_exponent_); else
sp.printf(" (< pow(2, %d+1))", max_exponent_);
}
} }
void 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 // than our newLower and newUpper. This is unusual, so we handle it here
// instead of in optimize(). // instead of in optimize().
// //
// For example, when the floating-point range has an actual maximum value // For example, consider the range F[0,1.5]. Range analysis represents the
// of 1.5, it may have a range like [0,2] and the max_exponent may be zero. // 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 // 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. // of the range is dropped. The max exponent of 0 remains valid, so the
if (lhs->canHaveFractionalPart_ != rhs->canHaveFractionalPart_) { // 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); refineInt32BoundsByExponent(newExponent, &newLower, &newUpper);
// If we're intersecting two ranges that don't overlap, this could also // If we're intersecting two ranges that don't overlap, this could also
@ -2424,3 +2458,13 @@ MNot::collectRangeInfo()
{ {
operandIsNeverNaN_ = !Range(operand()).canBeNaN(); 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++) { for (size_t i = 0; i < block->numPhis(); i++) {
InstructionInfo &info = blocks[blockIndex].phis[i]; InstructionInfo &info = blocks[blockIndex].phis[i];
LPhi *phi = block->getPhi(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++) for (size_t j = 0; j < phi->numOperands(); j++)
fprintf(stderr, " %s", info.inputs[j].toString()); fprintf(stderr, " %s", info.inputs[j].toString());
fprintf(stderr, "\n"); fprintf(stderr, "]\n");
} }
for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) { for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
@ -388,7 +393,10 @@ AllocationIntegrityState::dump()
CodePosition input(ins->id(), CodePosition::INPUT); CodePosition input(ins->id(), CodePosition::INPUT);
CodePosition output(ins->id(), CodePosition::OUTPUT); 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()) { if (ins->isMoveGroup()) {
LMoveGroup *group = ins->toMoveGroup(); LMoveGroup *group = ins->toMoveGroup();

View File

@ -328,6 +328,8 @@ class RegisterAllocator
return CodePosition(pos, CodePosition::INPUT); return CodePosition(pos, CodePosition::INPUT);
} }
CodePosition inputOf(const LInstruction *ins) const { 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); return CodePosition(ins->id(), CodePosition::INPUT);
} }
@ -341,17 +343,6 @@ class RegisterAllocator
return getMoveGroupAfter(pos.ins()); 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) { CodePosition minimalDefEnd(LInstruction *ins) {
// Compute the shortest interval that captures vregs defined by ins. // Compute the shortest interval that captures vregs defined by ins.
// Watch for instructions that are followed by an OSI point and/or Nop. // Watch for instructions that are followed by an OSI point and/or Nop.

View File

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

View File

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

View File

@ -551,19 +551,29 @@ CodeGeneratorX86Shared::visitPowHalfD(LPowHalfD *ins)
Label done, sqrt; Label done, sqrt;
// Branch if not -Infinity. if (!ins->mir()->operandIsNeverNegativeInfinity()) {
masm.loadConstantDouble(NegativeInfinity(), ScratchFloatReg); // Branch if not -Infinity.
masm.branchDouble(Assembler::DoubleNotEqualOrUnordered, input, ScratchFloatReg, &sqrt); masm.loadConstantDouble(NegativeInfinity(), ScratchFloatReg);
// Math.pow(-Infinity, 0.5) == Infinity. Assembler::DoubleCondition cond = Assembler::DoubleNotEqualOrUnordered;
masm.xorpd(input, input); if (ins->mir()->operandIsNeverNaN())
masm.subsd(ScratchFloatReg, input); cond = Assembler::DoubleNotEqual;
masm.jump(&done); 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.sqrtsd(input, input);
masm.bind(&done); masm.bind(&done);

View File

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

View File

@ -1437,43 +1437,21 @@ js_QuoteString(ExclusiveContext *cx, JSString *str, jschar quote)
static JSObject * static JSObject *
GetBlockChainAtPC(JSContext *cx, JSScript *script, jsbytecode *pc) 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; JSObject *blockChain = nullptr;
for (jsbytecode *p = start; p < pc; p += GetBytecodeLength(p)) { for (uint32_t n = 0; n < blockScopes->length; n++) {
JSOp op = JSOp(*p); const BlockScopeNote *note = &blockScopes->vector[n];
if (note->start > offset)
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;
break; break;
} if (offset <= note->start + note->length)
case JSOP_LEAVEBLOCK: blockChain = script->getObject(note->index);
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;
}
} }
return blockChain; return blockChain;

View File

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

View File

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

View File

@ -5796,6 +5796,10 @@ main(int argc, char **argv, char **envp)
"(default: 10)", -1) "(default: 10)", -1)
|| !op.addBoolOption('\0', "no-fpu", "Pretend CPU does not support floating-point operations " || !op.addBoolOption('\0', "no-fpu", "Pretend CPU does not support floating-point operations "
"to test JIT codegen (no-op on platforms other than x86).") "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 " || !op.addBoolOption('\0', "fuzzing-safe", "Don't expose functions that aren't safe for "
"fuzzers to call") "fuzzers to call")
#ifdef DEBUG #ifdef DEBUG
@ -5840,6 +5844,17 @@ main(int argc, char **argv, char **envp)
if (op.getBoolOption("no-fpu")) if (op.getBoolOption("no-fpu"))
JSC::MacroAssembler::SetFloatingPointDisabled(); JSC::MacroAssembler::SetFloatingPointDisabled();
#endif #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 #endif
// Start the engine. // 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()) if (!REGS.fp()->isYielding())
REGS.fp()->epilogue(cx); REGS.fp()->epilogue(cx);
else else
probes::ExitScript(cx, script, script->function(), REGS.fp()); probes::ExitScript(cx, script, script->function(), REGS.fp()->hasPushedSPSFrame());
#if defined(JS_ION) #if defined(JS_ION)
jit_return_pop_frame: jit_return_pop_frame:
@ -3437,7 +3437,7 @@ DEFAULT()
if (!REGS.fp()->isYielding()) if (!REGS.fp()->isYielding())
REGS.fp()->epilogue(cx); REGS.fp()->epilogue(cx);
else else
probes::ExitScript(cx, script, script->function(), REGS.fp()); probes::ExitScript(cx, script, script->function(), REGS.fp()->hasPushedSPSFrame());
gc::MaybeVerifyBarriers(cx, true); gc::MaybeVerifyBarriers(cx, true);

View File

@ -63,8 +63,7 @@ probes::EnterScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
} }
inline bool inline bool
probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun, probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun, bool popSPSFrame)
AbstractFramePtr fp)
{ {
bool ok = true; bool ok = true;
@ -76,22 +75,10 @@ probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
cx->doFunctionCallback(maybeFun, script, 0); cx->doFunctionCallback(maybeFun, script, 0);
#endif #endif
JSRuntime *rt = cx->runtime(); if (popSPSFrame)
/* cx->runtime()->spsProfiler.exit(cx, script, maybeFun);
* 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;
}
inline bool return ok;
probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
StackFrame *fp)
{
return probes::ExitScript(cx, script, maybeFun, fp ? AbstractFramePtr(fp) : AbstractFramePtr());
} }
inline bool inline bool

View File

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

View File

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

View File

@ -22,7 +22,7 @@ namespace js {
* and saved versions. If deserialization fails, the data should be * and saved versions. If deserialization fails, the data should be
* invalidated if possible. * 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 { class XDRBuffer {
public: public:

View File

@ -10,6 +10,7 @@
#include <stdio.h> #include <stdio.h>
#include "mozilla/Util.h" #include "mozilla/Util.h"
#include "mozilla/WindowsDllBlocklist.h"
#include "nsXULAppAPI.h" #include "nsXULAppAPI.h"
#ifdef XP_MACOSX #ifdef XP_MACOSX
@ -38,8 +39,8 @@ main(int argc, char** argv, char** envp)
setbuf(stdout, 0); setbuf(stdout, 0);
#endif #endif
#ifdef XRE_HAS_DLL_BLOCKLIST #ifdef HAS_DLL_BLOCKLIST
XRE_SetupDllBlocklist(); DllBlocklist_Initialize();
#endif #endif
int result = XRE_XPCShellMain(argc, argv, envp); 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 793848.html
load 795646.html load 795646.html
skip-if(1) load 802902.html # bug 901752 skip-if(1) load 802902.html # bug 901752
load 806056-1.html
load 806056-2.html
load 813372-1.html load 813372-1.html
asserts-if(gtk2Widget,0-1) load 822865.html # bug 540078 asserts-if(gtk2Widget,0-1) load 822865.html # bug 540078
load 833604-1.html load 833604-1.html

View File

@ -3455,6 +3455,9 @@ PresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent,
if (!targetView) if (!targetView)
return; return;
targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status); targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
if (MOZ_UNLIKELY(mIsDestroying)) {
return;
}
if (aFlushOnHoverChange && if (aFlushOnHoverChange &&
hoverGenerationBefore != restyleManager->GetHoverGeneration()) { hoverGenerationBefore != restyleManager->GetHoverGeneration()) {
// Flush so that the resulting reflow happens now so that our caller // 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 { virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE {
if (mPresShell) if (mPresShell) {
mPresShell->ProcessSynthMouseMoveEvent(mFromScroll); nsRefPtr<PresShell> shell = mPresShell;
shell->ProcessSynthMouseMoveEvent(mFromScroll);
}
} }
private: private:
PresShell* mPresShell; 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 387233-2.html
load 387282-1.html load 387282-1.html
load 388175-1.html load 388175-1.html
load 388367-1.html
load 388709-1.html load 388709-1.html
load 389635-1.html load 389635-1.html
load 390050-1.html load 390050-1.html
@ -169,7 +170,7 @@ load 398322-1.html
load 398322-2.html load 398322-2.html
load 398332-1.html load 398332-1.html
load 398332-2.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 399407-1.xhtml
load 399412-1.html load 399412-1.html
load 399843-1.html load 399843-1.html
@ -302,6 +303,7 @@ load 463350-1.html
load 463350-2.html load 463350-2.html
load 463350-3.html load 463350-3.html
load 463741-1.html load 463741-1.html
load 463785.xhtml
load 465651-1.html load 465651-1.html
load 467137-1.html load 467137-1.html
load 467213-1.html load 467213-1.html
@ -331,6 +333,7 @@ asserts-if(!Android,1) load 479938-1.html # Bug 575011
load 480345-1.html load 480345-1.html
skip-if(Android) load 481921.html skip-if(Android) load 481921.html
load 489462-1.html load 489462-1.html
load 489477.html
load 489480-1.xhtml load 489480-1.xhtml
load 493111-1.html load 493111-1.html
load 493118-1.html load 493118-1.html
@ -373,6 +376,7 @@ load 534082-1.html
load 534366-1.html load 534366-1.html
load 534366-2.html load 534366-2.html
load 536692-1.xhtml load 536692-1.xhtml
load 537645.xhtml
load 541277-1.html load 541277-1.html
load 541277-2.html load 541277-2.html
load 541714-1.html load 541714-1.html
@ -421,6 +425,8 @@ load 646561-1.html
load 646983-1.html load 646983-1.html
load 647332-1.html load 647332-1.html
load 650499-1.html load 650499-1.html
load 654002-1.html
load 654002-2.html
load 655462-1.html load 655462-1.html
load 656130-1.html load 656130-1.html
load 656130-2.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-1.html
load 769303-2.html load 769303-2.html
load 769120.html load 769120.html
load 777838.html
load 784600.html
load 786740-1.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 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 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-3a.html 387876-3-ref.html
== 387876-3b.html 387876-3-ref.html == 387876-3b.html 387876-3-ref.html
== 388026-1.html 388026-1-ref.html == 388026-1.html 388026-1-ref.html
== 388367-1.html about:blank
== 389074-1.html 389074-1-ref.html == 389074-1.html 389074-1-ref.html
== 389224-1.html 389224-1-ref.html == 389224-1.html 389224-1-ref.html
== 389224-2.html about:blank == 389224-2.html about:blank

View File

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

View File

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

View File

@ -5,18 +5,15 @@
#include <windows.h> #include <windows.h>
#include <winternl.h> #include <winternl.h>
#include <io.h>
#include <stdio.h> #pragma warning( push )
#include <string.h> #pragma warning( disable : 4275 4530 ) // See msvc-stl-wrapper.template.h
#include <map> #include <map>
#pragma warning( pop )
#include "nsXULAppAPI.h" #define MOZ_NO_MOZALLOC
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "prlog.h"
#include "nsWindowsDllInterceptor.h" #include "nsWindowsDllInterceptor.h"
#include "mozilla/WindowsVersion.h" #include "mozilla/WindowsVersion.h"
@ -24,10 +21,6 @@
using namespace mozilla; using namespace mozilla;
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
#define ALL_VERSIONS ((unsigned long long)-1LL) #define ALL_VERSIONS ((unsigned long long)-1LL)
// DLLs sometimes ship without a version number, particularly early // 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 // define this for very verbose dll load debug spew
#undef DEBUG_very_verbose #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 { namespace {
@ -170,7 +203,7 @@ struct RVAMap {
DWORD alignedOffset = (offset / info.dwAllocationGranularity) * DWORD alignedOffset = (offset / info.dwAllocationGranularity) *
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, mRealView = ::MapViewOfFile(map, FILE_MAP_READ, 0, alignedOffset,
sizeof(T) + (offset - alignedOffset)); sizeof(T) + (offset - alignedOffset));
@ -544,7 +577,7 @@ continue_loading:
printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer); printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer);
#endif #endif
if (gInXPCOMLoadOnMainThread && NS_IsMainThread()) { if (GetCurrentThreadId() == sThreadLoadingXPCOMModule) {
// Check to ensure that the DLL has ASLR. // Check to ensure that the DLL has ASLR.
full_fname = getFullPath(filePath, fname); full_fname = getFullPath(filePath, fname);
if (!full_fname) { if (!full_fname) {
@ -566,31 +599,56 @@ WindowsDllInterceptor NtDllIntercept;
} // anonymous namespace } // anonymous namespace
void NS_EXPORT void
XRE_SetupDllBlocklist() DllBlocklist_Initialize()
{ {
if (GetModuleHandleA("user32.dll")) {
sUser32BeforeBlocklist = true;
}
NtDllIntercept.Init("ntdll.dll"); NtDllIntercept.Init("ntdll.dll");
ReentrancySentinel::InitializeStatics(); ReentrancySentinel::InitializeStatics();
bool ok = NtDllIntercept.AddHook("LdrLoadDll", reinterpret_cast<intptr_t>(patched_LdrLoadDll), (void**) &stub_LdrLoadDll); bool ok = NtDllIntercept.AddHook("LdrLoadDll", reinterpret_cast<intptr_t>(patched_LdrLoadDll), (void**) &stub_LdrLoadDll);
if (!ok) {
sBlocklistInitFailed = true;
#ifdef DEBUG #ifdef DEBUG
if (!ok)
printf_stderr ("LdrLoadDll hook failed, no dll blocklisting active\n"); printf_stderr ("LdrLoadDll hook failed, no dll blocklisting active\n");
#endif #endif
#ifdef MOZ_CRASHREPORTER
if (!ok) {
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DllBlockList Failed\n"));
} }
#endif
} }
#ifdef MOZ_CRASHREPORTER NS_EXPORT void
void DllBlocklist_SetInXPCOMLoadOnMainThread(bool inXPCOMLoadOnMainThread)
CrashReporter::WriteBlockedDlls(HANDLE file)
{ {
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', 'BionicGlue.cpp',
] ]
if CONFIG['OS_TARGET'] == 'WINNT':
SOURCES += [
'WindowsDllBlocklist.cpp',
]
if CONFIG['MOZ_NUWA_PROCESS']: if CONFIG['MOZ_NUWA_PROCESS']:
EXPORTS.ipc += [ EXPORTS.ipc += [
'Nuwa.h', 'Nuwa.h',
@ -42,6 +47,7 @@ if CONFIG['MOZ_NUWA_PROCESS']:
EXPORTS.mozilla += [ EXPORTS.mozilla += [
'arm.h', 'arm.h',
'SSE.h', 'SSE.h',
'WindowsDllBlocklist.h',
] ]
if CONFIG['CPU_ARCH'].startswith('x86'): if CONFIG['CPU_ARCH'].startswith('x86'):

View File

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

View File

@ -44,11 +44,6 @@ nsresult AppendAppNotesToCrashReport(const nsACString& data);
nsresult SetGarbageCollecting(bool collecting); 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 SetRestartArgs(int argc, char** argv);
nsresult SetupExtraData(nsIFile* aAppDataDirectory, nsresult SetupExtraData(nsIFile* aAppDataDirectory,
const nsACString& aBuildID); const nsACString& aBuildID);

View File

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

View File

@ -12,6 +12,8 @@
#include <gio/gio.h> #include <gio/gio.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
char * char *
@ -377,6 +379,56 @@ nsGIOService::ShowURIForInput(const nsACString& aUri)
return rv; 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 * Create or find already existing application info for specified command
* and application name. * and application name.

View File

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

View File

@ -11,24 +11,10 @@
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
#include <fstream>
#include "platform.h" #include "platform.h"
#include "shared-libraries.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) #if !defined(MOZ_WIDGET_GONK)
// TODO fix me with proper include // TODO fix me with proper include
#include "nsDebug.h" #include "nsDebug.h"
@ -91,11 +77,10 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
pid_t pid = getpid(); pid_t pid = getpid();
char path[PATH_MAX]; char path[PATH_MAX];
snprintf(path, PATH_MAX, "/proc/%d/maps", pid); snprintf(path, PATH_MAX, "/proc/%d/maps", pid);
FILE *maps = fopen(path, "r"); std::ifstream maps(path);
char *line = NULL; std::string line;
int count = 0; int count = 0;
size_t line_size = 0; while (std::getline(maps, line)) {
while (maps && getline (&line, &line_size, maps) > 0) {
int ret; int ret;
//XXX: needs input sanitizing //XXX: needs input sanitizing
unsigned long start; unsigned long start;
@ -103,7 +88,7 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
char perm[6] = ""; char perm[6] = "";
unsigned long offset; unsigned long offset;
char name[PATH_MAX] = ""; 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", "%lx-%lx %6s %lx %*s %*x %" PATH_MAX_STRING(PATH_MAX) "s\n",
&start, &end, perm, &offset, name); &start, &end, perm, &offset, name);
if (!strchr(perm, 'x')) { if (!strchr(perm, 'x')) {
@ -128,6 +113,5 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
} }
count++; count++;
} }
free(line);
return info; return info;
} }

View File

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

View File

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

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