mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b2g-inbound.
This commit is contained in:
commit
ea3219930a
@ -42,6 +42,7 @@
|
||||
#endif
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
static void Output(const char *fmt, ... )
|
||||
{
|
||||
@ -92,9 +93,6 @@ public:
|
||||
XRE_GetFileFromPathType XRE_GetFileFromPath;
|
||||
XRE_CreateAppDataType XRE_CreateAppData;
|
||||
XRE_FreeAppDataType XRE_FreeAppData;
|
||||
#ifdef XRE_HAS_DLL_BLOCKLIST
|
||||
XRE_SetupDllBlocklistType XRE_SetupDllBlocklist;
|
||||
#endif
|
||||
XRE_TelemetryAccumulateType XRE_TelemetryAccumulate;
|
||||
XRE_mainType XRE_main;
|
||||
|
||||
@ -102,9 +100,6 @@ static const nsDynamicFunctionLoad kXULFuncs[] = {
|
||||
{ "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
|
||||
{ "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
|
||||
{ "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
|
||||
#ifdef XRE_HAS_DLL_BLOCKLIST
|
||||
{ "XRE_SetupDllBlocklist", (NSFuncPtr*) &XRE_SetupDllBlocklist },
|
||||
#endif
|
||||
{ "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
|
||||
{ "XRE_main", (NSFuncPtr*) &XRE_main },
|
||||
{ nullptr, nullptr }
|
||||
@ -210,6 +205,10 @@ int main(int argc, char* argv[])
|
||||
gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DLL_BLOCKLIST
|
||||
DllBlocklist_Initialize();
|
||||
#endif
|
||||
|
||||
// We do this because of data in bug 771745
|
||||
XPCOMGlueEnablePreload();
|
||||
|
||||
@ -227,10 +226,6 @@ int main(int argc, char* argv[])
|
||||
return 255;
|
||||
}
|
||||
|
||||
#ifdef XRE_HAS_DLL_BLOCKLIST
|
||||
XRE_SetupDllBlocklist();
|
||||
#endif
|
||||
|
||||
if (gotCounters) {
|
||||
#if defined(XP_WIN)
|
||||
XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS,
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -78,9 +79,19 @@ static void Output(const char *fmt, ... )
|
||||
#if MOZ_WINCONSOLE
|
||||
fwprintf_s(stderr, wide_msg);
|
||||
#else
|
||||
MessageBoxW(nullptr, wide_msg, L"Firefox", MB_OK
|
||||
| MB_ICONERROR
|
||||
| MB_SETFOREGROUND);
|
||||
// Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
|
||||
// This is a rare codepath, so we can load user32 at run-time instead.
|
||||
HMODULE user32 = LoadLibraryW(L"user32.dll");
|
||||
if (user32) {
|
||||
typedef int (WINAPI * MessageBoxWFn)(HWND, LPCWSTR, LPCWSTR, UINT);
|
||||
MessageBoxWFn messageBoxW = (MessageBoxWFn)GetProcAddress(user32, "MessageBoxW");
|
||||
if (messageBoxW) {
|
||||
messageBoxW(nullptr, wide_msg, L"Firefox", MB_OK
|
||||
| MB_ICONERROR
|
||||
| MB_SETFOREGROUND);
|
||||
}
|
||||
FreeLibrary(user32);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -144,9 +155,6 @@ static void AttachToTestHarness()
|
||||
XRE_GetFileFromPathType XRE_GetFileFromPath;
|
||||
XRE_CreateAppDataType XRE_CreateAppData;
|
||||
XRE_FreeAppDataType XRE_FreeAppData;
|
||||
#ifdef XRE_HAS_DLL_BLOCKLIST
|
||||
XRE_SetupDllBlocklistType XRE_SetupDllBlocklist;
|
||||
#endif
|
||||
XRE_TelemetryAccumulateType XRE_TelemetryAccumulate;
|
||||
XRE_StartupTimelineRecordType XRE_StartupTimelineRecord;
|
||||
XRE_mainType XRE_main;
|
||||
@ -156,9 +164,6 @@ static const nsDynamicFunctionLoad kXULFuncs[] = {
|
||||
{ "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
|
||||
{ "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
|
||||
{ "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData },
|
||||
#ifdef XRE_HAS_DLL_BLOCKLIST
|
||||
{ "XRE_SetupDllBlocklist", (NSFuncPtr*) &XRE_SetupDllBlocklist },
|
||||
#endif
|
||||
{ "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate },
|
||||
{ "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord },
|
||||
{ "XRE_main", (NSFuncPtr*) &XRE_main },
|
||||
@ -597,6 +602,17 @@ int main(int argc, char* argv[])
|
||||
|
||||
nsIFile *xreDirectory;
|
||||
|
||||
#ifdef HAS_DLL_BLOCKLIST
|
||||
DllBlocklist_Initialize();
|
||||
|
||||
// In order to be effective against AppInit DLLs, the blocklist must be
|
||||
// initialized before user32.dll is loaded into the process. If this assert
|
||||
// ever fires, then the fix for bug 932100 has been defeated and the
|
||||
// blocklist will miss AppInit DLLs. You should use a delayload or reorder
|
||||
// the code to prevent user32.dll from loading during early startup.
|
||||
MOZ_ASSERT(!GetModuleHandleA("user32.dll"));
|
||||
#endif
|
||||
|
||||
nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory);
|
||||
if (NS_FAILED(rv)) {
|
||||
return 255;
|
||||
@ -604,10 +620,6 @@ int main(int argc, char* argv[])
|
||||
|
||||
XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
|
||||
|
||||
#ifdef XRE_HAS_DLL_BLOCKLIST
|
||||
XRE_SetupDllBlocklist();
|
||||
#endif
|
||||
|
||||
if (gotCounters) {
|
||||
#if defined(XP_WIN)
|
||||
XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS,
|
||||
|
@ -800,7 +800,7 @@ else # !WINNT || GNU_CC
|
||||
endif # WINNT && !GNU_CC
|
||||
|
||||
ifdef ENABLE_STRIP
|
||||
$(STRIP) $@
|
||||
$(STRIP) $(STRIP_FLAGS) $@
|
||||
endif
|
||||
ifdef MOZ_POST_PROGRAM_COMMAND
|
||||
$(MOZ_POST_PROGRAM_COMMAND) $@
|
||||
@ -856,7 +856,7 @@ else
|
||||
endif # WINNT && !GNU_CC
|
||||
|
||||
ifdef ENABLE_STRIP
|
||||
$(STRIP) $@
|
||||
$(STRIP) $(STRIP_FLAGS) $@
|
||||
endif
|
||||
ifdef MOZ_POST_PROGRAM_COMMAND
|
||||
$(MOZ_POST_PROGRAM_COMMAND) $@
|
||||
@ -883,7 +883,6 @@ $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
|
||||
$(REPORT_BUILD)
|
||||
$(RM) $(LIBRARY)
|
||||
$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(SHARED_LIBRARY_LIBS)
|
||||
$(RANLIB) $@
|
||||
|
||||
$(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
|
||||
# When we only build a library descriptor, blow out any existing library
|
||||
@ -917,14 +916,12 @@ $(IMPORT_LIBRARY): $(SHARED_LIBRARY)
|
||||
$(REPORT_BUILD)
|
||||
$(RM) $@
|
||||
$(IMPLIB) $@ $^
|
||||
$(RANLIB) $@
|
||||
endif # OS/2
|
||||
|
||||
$(HOST_LIBRARY): $(HOST_OBJS) Makefile
|
||||
$(REPORT_BUILD)
|
||||
$(RM) $@
|
||||
$(EXPAND_LIBS_EXEC) --extract -- $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
|
||||
$(HOST_RANLIB) $@
|
||||
|
||||
ifdef HAVE_DTRACE
|
||||
ifndef XP_MACOSX
|
||||
@ -975,7 +972,7 @@ endif # WINNT && !GCC
|
||||
@$(RM) foodummyfilefoo $(DELETE_AFTER_LINK)
|
||||
chmod +x $@
|
||||
ifdef ENABLE_STRIP
|
||||
$(STRIP) $@
|
||||
$(STRIP) $(STRIP_FLAGS) $@
|
||||
endif
|
||||
ifdef MOZ_POST_DSO_LIB_COMMAND
|
||||
$(MOZ_POST_DSO_LIB_COMMAND) $@
|
||||
|
24
configure.in
24
configure.in
@ -306,7 +306,7 @@ dnl to use the cross-compile setup for now
|
||||
dnl ========================================================
|
||||
|
||||
dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269)
|
||||
AR_FLAGS='cr $@'
|
||||
AR_FLAGS='crs $@'
|
||||
|
||||
if test "$COMPILE_ENVIRONMENT"; then
|
||||
|
||||
@ -8872,7 +8872,27 @@ dnl so that regeneration via dependencies works correctly
|
||||
WEBRTC_CONFIG="${WEBRTC_CONFIG} -D have_ethtool_cmd_speed_hi=0"
|
||||
fi
|
||||
|
||||
GYP_WEBRTC_OPTIONS="--format=mozmake ${WEBRTC_CONFIG} -D target_arch=${WEBRTC_TARGET_ARCH} ${EXTRA_GYP_DEFINES} --depth=${srcdir}/media/webrtc/trunk --toplevel-dir=${srcdir} -G OBJDIR=${_objdir}"
|
||||
if test -n "$CROSS_COMPILE"; then
|
||||
case "$target" in
|
||||
*-mingw*)
|
||||
GYP_MOZMAKE_OPTIONS="-G os=win"
|
||||
;;
|
||||
*-darwin*)
|
||||
GYP_MOZMAKE_OPTIONS="-G os=mac"
|
||||
if test "$MACOS_SDK_DIR"; then
|
||||
GYP_MOZMAKE_OPTIONS="${GYP_MOZMAKE_OPTIONS} -D mac_sdk_path=$MACOS_SDK_DIR"
|
||||
fi
|
||||
;;
|
||||
*-android*)
|
||||
GYP_MOZMAKE_OPTIONS="-G os=linux"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Don't know what options to give to WebRTC for cross-compilation])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
GYP_WEBRTC_OPTIONS="--format=mozmake ${GYP_MOZMAKE_OPTIONS} ${WEBRTC_CONFIG} -D target_arch=${WEBRTC_TARGET_ARCH} ${EXTRA_GYP_DEFINES} --depth=${srcdir}/media/webrtc/trunk --toplevel-dir=${srcdir} -G OBJDIR=${_objdir}"
|
||||
|
||||
$PYTHON ${srcdir}/media/webrtc/trunk/build/gyp_chromium \
|
||||
$GYP_WEBRTC_OPTIONS \
|
||||
|
@ -15,12 +15,14 @@
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{'set':[["security.csp.speccompliant", true]]},
|
||||
function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var testframe = document.getElementById('testframe');
|
||||
testframe.src = 'file_policyuri_regression_from_multipolicy.html';
|
||||
testframe.addEventListener('load', function checkInlineScriptExecuted () {
|
||||
is(this.contentDocument.getElementById('testdiv').innerHTML,
|
||||
'Inline Script Executed',
|
||||
'Inline script should execute (it would be blocked by the policy, but the policy is report-only)');
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -2716,6 +2716,7 @@ WebGLContext::Uniform1i(WebGLUniformLocation *location_object, GLint a1)
|
||||
if (!ValidateUniformSetter("Uniform1i", location_object, location))
|
||||
return;
|
||||
|
||||
// Only uniform1i can take sampler settings.
|
||||
if (!ValidateSamplerUniformSetter("Uniform1i", location_object, a1))
|
||||
return;
|
||||
|
||||
@ -2731,12 +2732,6 @@ WebGLContext::Uniform2i(WebGLUniformLocation *location_object, GLint a1,
|
||||
if (!ValidateUniformSetter("Uniform2i", location_object, location))
|
||||
return;
|
||||
|
||||
if (!ValidateSamplerUniformSetter("Uniform2i", location_object, a1) ||
|
||||
!ValidateSamplerUniformSetter("Uniform2i", location_object, a2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform2i(location, a1, a2);
|
||||
}
|
||||
@ -2749,13 +2744,6 @@ WebGLContext::Uniform3i(WebGLUniformLocation *location_object, GLint a1,
|
||||
if (!ValidateUniformSetter("Uniform3i", location_object, location))
|
||||
return;
|
||||
|
||||
if (!ValidateSamplerUniformSetter("Uniform3i", location_object, a1) ||
|
||||
!ValidateSamplerUniformSetter("Uniform3i", location_object, a2) ||
|
||||
!ValidateSamplerUniformSetter("Uniform3i", location_object, a3))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform3i(location, a1, a2, a3);
|
||||
}
|
||||
@ -2768,14 +2756,6 @@ WebGLContext::Uniform4i(WebGLUniformLocation *location_object, GLint a1,
|
||||
if (!ValidateUniformSetter("Uniform4i", location_object, location))
|
||||
return;
|
||||
|
||||
if (!ValidateSamplerUniformSetter("Uniform4i", location_object, a1) ||
|
||||
!ValidateSamplerUniformSetter("Uniform4i", location_object, a2) ||
|
||||
!ValidateSamplerUniformSetter("Uniform4i", location_object, a3) ||
|
||||
!ValidateSamplerUniformSetter("Uniform4i", location_object, a4))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform4i(location, a1, a2, a3, a4);
|
||||
}
|
||||
|
@ -8,8 +8,8 @@
|
||||
</head>
|
||||
<script type="application/javascript">
|
||||
function doTest() {
|
||||
sendMouseEvent({type:'click'}, 'anchor');
|
||||
window.parent.postMessage({type: "attempted"}, "*");
|
||||
sendMouseEvent({type:'click'}, 'anchor');
|
||||
}
|
||||
</script>
|
||||
<body onload="doTest()">
|
||||
|
@ -267,8 +267,8 @@ function doIf10TestPart2() {
|
||||
<iframe sandbox="allow-scripts" id="if_1" src="file_iframe_sandbox_d_if1.html" height="10" width="10"></iframe>
|
||||
<iframe sandbox="allow-scripts" id="if_2" src="file_iframe_sandbox_d_if2.html" height="10" width="10"></iframe>
|
||||
<iframe sandbox="allow-scripts" id="if_3" src="file_iframe_sandbox_d_if3.html" height="10" width="10"></iframe>
|
||||
<iframe id="if_sibling" name="if_sibling" src="about:blank" height="10" width="10"></iframe>
|
||||
<iframe sandbox="allow-scripts allow-same-origin" id="if_5" src="file_iframe_sandbox_d_if5.html" height="10" width="10"></iframe>
|
||||
<iframe id="if_sibling" name="if_sibling" src="file_iframe_sandbox_navigation_start.html" height="10" width="10"></iframe>
|
||||
<iframe sandbox="allow-scripts" id="if_6" src="file_iframe_sandbox_d_if6.html" height="10" width="10"></iframe>
|
||||
<iframe sandbox="allow-same-origin allow-scripts" id="if_8" src="file_iframe_sandbox_d_if8.html" height="10" width="10"></iframe>
|
||||
<iframe sandbox="allow-same-origin allow-scripts" id="if_9" src="file_iframe_sandbox_d_if9.html" height="10" width="10"></iframe>
|
||||
|
@ -55,7 +55,8 @@ public:
|
||||
{
|
||||
}
|
||||
NS_IMETHOD_(void) DescribeGCedNode(bool aIsMarked,
|
||||
const char* aObjName)
|
||||
const char* aObjName,
|
||||
uint64_t aCompartmentAddress)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -490,13 +490,17 @@ RTCPeerConnection.prototype = {
|
||||
constraints = {};
|
||||
}
|
||||
this._mustValidateConstraints(constraints, "createOffer passed invalid constraints");
|
||||
this._onCreateOfferSuccess = onSuccess;
|
||||
this._onCreateOfferFailure = onError;
|
||||
|
||||
this._queueOrRun({ func: this._createOffer, args: [constraints], wait: true });
|
||||
this._queueOrRun({
|
||||
func: this._createOffer,
|
||||
args: [onSuccess, onError, constraints],
|
||||
wait: true
|
||||
});
|
||||
},
|
||||
|
||||
_createOffer: function(constraints) {
|
||||
_createOffer: function(onSuccess, onError, constraints) {
|
||||
this._onCreateOfferSuccess = onSuccess;
|
||||
this._onCreateOfferFailure = onError;
|
||||
this._getPC().createOffer(constraints);
|
||||
},
|
||||
|
||||
@ -542,12 +546,6 @@ RTCPeerConnection.prototype = {
|
||||
},
|
||||
|
||||
setLocalDescription: function(desc, onSuccess, onError) {
|
||||
// TODO -- if we have two setLocalDescriptions in the
|
||||
// queue,this code overwrites the callbacks for the first
|
||||
// one with the callbacks for the second one. See Bug 831759.
|
||||
this._onSetLocalDescriptionSuccess = onSuccess;
|
||||
this._onSetLocalDescriptionFailure = onError;
|
||||
|
||||
let type;
|
||||
switch (desc.type) {
|
||||
case "offer":
|
||||
@ -565,23 +563,19 @@ RTCPeerConnection.prototype = {
|
||||
|
||||
this._queueOrRun({
|
||||
func: this._setLocalDescription,
|
||||
args: [type, desc.sdp],
|
||||
args: [type, desc.sdp, onSuccess, onError],
|
||||
wait: true,
|
||||
type: desc.type
|
||||
});
|
||||
},
|
||||
|
||||
_setLocalDescription: function(type, sdp) {
|
||||
_setLocalDescription: function(type, sdp, onSuccess, onError) {
|
||||
this._onSetLocalDescriptionSuccess = onSuccess;
|
||||
this._onSetLocalDescriptionFailure = onError;
|
||||
this._getPC().setLocalDescription(type, sdp);
|
||||
},
|
||||
|
||||
setRemoteDescription: function(desc, onSuccess, onError) {
|
||||
// TODO -- if we have two setRemoteDescriptions in the
|
||||
// queue, this code overwrites the callbacks for the first
|
||||
// one with the callbacks for the second one. See Bug 831759.
|
||||
this._onSetRemoteDescriptionSuccess = onSuccess;
|
||||
this._onSetRemoteDescriptionFailure = onError;
|
||||
|
||||
let type;
|
||||
switch (desc.type) {
|
||||
case "offer":
|
||||
@ -599,13 +593,15 @@ RTCPeerConnection.prototype = {
|
||||
|
||||
this._queueOrRun({
|
||||
func: this._setRemoteDescription,
|
||||
args: [type, desc.sdp],
|
||||
args: [type, desc.sdp, onSuccess, onError],
|
||||
wait: true,
|
||||
type: desc.type
|
||||
});
|
||||
},
|
||||
|
||||
_setRemoteDescription: function(type, sdp) {
|
||||
_setRemoteDescription: function(type, sdp, onSuccess, onError) {
|
||||
this._onSetRemoteDescriptionSuccess = onSuccess;
|
||||
this._onSetRemoteDescriptionFailure = onError;
|
||||
this._getPC().setRemoteDescription(type, sdp);
|
||||
},
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
MODULE = 'editor'
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsComposerCommands.cpp',
|
||||
'nsComposerCommandsUpdater.cpp',
|
||||
'nsComposerController.cpp',
|
||||
|
@ -23,10 +23,6 @@
|
||||
#include "nsAString.h"
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool gNoisy = false;
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
CreateElementTxn::CreateElementTxn()
|
||||
@ -61,16 +57,6 @@ NS_IMETHODIMP CreateElementTxn::Init(nsEditor *aEditor,
|
||||
|
||||
NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
char* nodename = ToNewCString(mTag);
|
||||
printf("Do Create Element parent = %p <%s>, offset = %d\n",
|
||||
static_cast<void*>(mParent.get()), nodename, mOffsetInParent);
|
||||
nsMemory::Free(nodename);
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(mEditor && mParent, "bad state");
|
||||
NS_ENSURE_TRUE(mEditor && mParent, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
@ -85,13 +71,6 @@ NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
|
||||
// Try to insert formatting whitespace for the new node:
|
||||
mEditor->MarkNodeDirty(mNewNode);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf(" newNode = %p\n", static_cast<void*>(mNewNode.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
// insert the new node
|
||||
if (CreateElementTxn::eAppend == int32_t(mOffsetInParent)) {
|
||||
ErrorResult rv;
|
||||
@ -133,15 +112,6 @@ NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
|
||||
|
||||
NS_IMETHODIMP CreateElementTxn::UndoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("Undo Create Element, mParent = %p, node = %p\n",
|
||||
static_cast<void*>(mParent.get()),
|
||||
static_cast<void*>(mNewNode.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(mEditor && mParent, "bad state");
|
||||
NS_ENSURE_TRUE(mEditor && mParent, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
@ -152,10 +122,6 @@ NS_IMETHODIMP CreateElementTxn::UndoTransaction(void)
|
||||
|
||||
NS_IMETHODIMP CreateElementTxn::RedoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy) { printf("Redo Create Element\n"); }
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(mEditor && mParent, "bad state");
|
||||
NS_ENSURE_TRUE(mEditor && mParent, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
|
@ -19,11 +19,6 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool gNoisy = false;
|
||||
#endif
|
||||
|
||||
|
||||
InsertElementTxn::InsertElementTxn()
|
||||
: EditTxn()
|
||||
{
|
||||
@ -57,23 +52,6 @@ NS_IMETHODIMP InsertElementTxn::Init(nsINode *aNode,
|
||||
|
||||
NS_IMETHODIMP InsertElementTxn::DoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
nsCOMPtr<nsIContent>nodeAsContent = do_QueryInterface(mNode);
|
||||
nsCOMPtr<nsIContent>parentAsContent = do_QueryInterface(mParent);
|
||||
nsString namestr = mNode->NodeName();
|
||||
char* nodename = ToNewCString(namestr);
|
||||
printf("%p Do Insert Element of %p <%s> into parent %p at offset %d\n",
|
||||
static_cast<void*>(this),
|
||||
static_cast<void*>(nodeAsContent.get()),
|
||||
nodename,
|
||||
static_cast<void*>(parentAsContent.get()),
|
||||
mOffset);
|
||||
nsMemory::Free(nodename);
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ENSURE_TRUE(mNode && mParent, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsINode> parent = do_QueryInterface(mParent);
|
||||
@ -115,17 +93,6 @@ NS_IMETHODIMP InsertElementTxn::DoTransaction(void)
|
||||
|
||||
NS_IMETHODIMP InsertElementTxn::UndoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("%p Undo Insert Element of %p into parent %p at offset %d\n",
|
||||
static_cast<void*>(this),
|
||||
static_cast<void*>(mNode.get()),
|
||||
static_cast<void*>(mParent.get()),
|
||||
mOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ENSURE_TRUE(mNode && mParent, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
ErrorResult rv;
|
||||
|
@ -15,10 +15,6 @@
|
||||
#include "nsISupportsUtils.h" // for NS_ADDREF_THIS, NS_RELEASE
|
||||
#include "nsITransaction.h" // for nsITransaction
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool gNoisy = false;
|
||||
#endif
|
||||
|
||||
InsertTextTxn::InsertTextTxn()
|
||||
: EditTxn()
|
||||
{
|
||||
@ -62,14 +58,6 @@ NS_IMETHODIMP InsertTextTxn::Init(nsIDOMCharacterData *aElement,
|
||||
|
||||
NS_IMETHODIMP InsertTextTxn::DoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("Do Insert Text element = %p\n",
|
||||
static_cast<void*>(mElement.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(mElement && mEditor, "bad state");
|
||||
if (!mElement || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
@ -98,14 +86,6 @@ NS_IMETHODIMP InsertTextTxn::DoTransaction(void)
|
||||
|
||||
NS_IMETHODIMP InsertTextTxn::UndoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("Undo Insert Text element = %p\n",
|
||||
static_cast<void*>(mElement.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(mElement && mEditor, "bad state");
|
||||
if (!mElement || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
@ -133,13 +113,6 @@ NS_IMETHODIMP InsertTextTxn::Merge(nsITransaction *aTransaction, bool *aDidMerge
|
||||
otherInsTxn->GetData(otherData);
|
||||
mStringToInsert += otherData;
|
||||
*aDidMerge = true;
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("InsertTextTxn assimilated %p\n",
|
||||
static_cast<void*>(aTransaction));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
NS_RELEASE(otherInsTxn);
|
||||
}
|
||||
|
@ -17,10 +17,6 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool gNoisy = false;
|
||||
#endif
|
||||
|
||||
JoinElementTxn::JoinElementTxn()
|
||||
: EditTxn()
|
||||
{
|
||||
@ -54,16 +50,6 @@ NS_IMETHODIMP JoinElementTxn::Init(nsEditor *aEditor,
|
||||
// After DoTransaction() and RedoTransaction(), the left node is removed from the content tree and right node remains.
|
||||
NS_IMETHODIMP JoinElementTxn::DoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("%p Do Join of %p and %p\n",
|
||||
static_cast<void*>(this),
|
||||
static_cast<void*>(mLeftNode.get()),
|
||||
static_cast<void*>(mRightNode.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_PRECONDITION((mEditor && mLeftNode && mRightNode), "null arg");
|
||||
if (!mEditor || !mLeftNode || !mRightNode) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
@ -85,30 +71,13 @@ NS_IMETHODIMP JoinElementTxn::DoTransaction(void)
|
||||
mParent = leftParent;
|
||||
mOffset = mLeftNode->Length();
|
||||
|
||||
nsresult rv = mEditor->JoinNodesImpl(mRightNode, mLeftNode, mParent);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (NS_SUCCEEDED(rv) && gNoisy) {
|
||||
printf(" left node = %p removed\n", static_cast<void*>(mLeftNode.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
return mEditor->JoinNodesImpl(mRightNode, mLeftNode, mParent);
|
||||
}
|
||||
|
||||
//XXX: what if instead of split, we just deleted the unneeded children of mRight
|
||||
// and re-inserted mLeft?
|
||||
NS_IMETHODIMP JoinElementTxn::UndoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("%p Undo Join, right node = %p\n",
|
||||
static_cast<void*>(this),
|
||||
static_cast<void*>(mRightNode.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(mRightNode && mLeftNode && mParent, "bad state");
|
||||
if (!mRightNode || !mLeftNode || !mParent) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
// first, massage the existing node so it is in its post-split state
|
||||
|
@ -18,11 +18,6 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool gNoisy = false;
|
||||
#endif
|
||||
|
||||
|
||||
// note that aEditor is not refcounted
|
||||
SplitElementTxn::SplitElementTxn()
|
||||
: EditTxn()
|
||||
@ -53,16 +48,6 @@ NS_IMETHODIMP SplitElementTxn::Init(nsEditor *aEditor,
|
||||
|
||||
NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("%p Do Split of node %p offset %d\n",
|
||||
static_cast<void*>(this),
|
||||
static_cast<void*>(mExistingRightNode.get()),
|
||||
mOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(mExistingRightNode && mEditor, "bad state");
|
||||
if (!mExistingRightNode || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
@ -74,14 +59,6 @@ NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
|
||||
NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NULL_POINTER);
|
||||
mEditor->MarkNodeDirty(mExistingRightNode);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf(" created left node = %p\n",
|
||||
static_cast<void*>(mNewLeftNode.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
// get the parent node
|
||||
mParent = mExistingRightNode->GetParentNode();
|
||||
NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER);
|
||||
@ -113,43 +90,13 @@ NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
|
||||
|
||||
NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisy) {
|
||||
printf("%p Undo Split of existing node %p and new node %p offset %d\n",
|
||||
static_cast<void*>(this),
|
||||
static_cast<void*>(mExistingRightNode.get()),
|
||||
static_cast<void*>(mNewLeftNode.get()),
|
||||
mOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state");
|
||||
if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// this assumes Do inserted the new node in front of the prior existing node
|
||||
nsresult rv = mEditor->JoinNodesImpl(mExistingRightNode, mNewLeftNode,
|
||||
mParent);
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("** after join left child node %p into right node %p\n",
|
||||
static_cast<void*>(mNewLeftNode.get()),
|
||||
static_cast<void*>(mExistingRightNode.get()));
|
||||
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
|
||||
}
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
if (gNoisy)
|
||||
{
|
||||
printf(" left node = %p removed\n",
|
||||
static_cast<void*>(mNewLeftNode.get()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
return mEditor->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent);
|
||||
}
|
||||
|
||||
/* redo cannot simply resplit the right node, because subsequent transactions
|
||||
@ -162,32 +109,12 @@ NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (gNoisy) {
|
||||
printf("%p Redo Split of existing node %p and new node %p offset %d\n",
|
||||
static_cast<void*>(this),
|
||||
static_cast<void*>(mExistingRightNode.get()),
|
||||
static_cast<void*>(mNewLeftNode.get()),
|
||||
mOffset);
|
||||
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
|
||||
}
|
||||
#endif
|
||||
|
||||
// first, massage the existing node so it is in its post-split state
|
||||
nsCOMPtr<nsIDOMCharacterData>rightNodeAsText = do_QueryInterface(mExistingRightNode);
|
||||
if (rightNodeAsText)
|
||||
{
|
||||
nsresult result = rightNodeAsText->DeleteData(0, mOffset);
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("** after delete of text in right text node %p offset %d\n",
|
||||
static_cast<void*>(rightNodeAsText.get()),
|
||||
mOffset);
|
||||
mEditor->DebugDumpContent(); // DEBUG
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -201,16 +128,6 @@ NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
|
||||
{
|
||||
mNewLeftNode->AppendChild(*child, rv);
|
||||
NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("** move child node %p from right node %p to left node %p\n",
|
||||
static_cast<void*>(child),
|
||||
static_cast<void*>(mExistingRightNode.get()),
|
||||
static_cast<void*>(mNewLeftNode.get()));
|
||||
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
|
||||
}
|
||||
#endif
|
||||
}
|
||||
child = child->GetNextSibling();
|
||||
}
|
||||
@ -218,15 +135,6 @@ NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
|
||||
// second, re-insert the left node into the tree
|
||||
ErrorResult rv;
|
||||
mParent->InsertBefore(*mNewLeftNode, mExistingRightNode, rv);
|
||||
#ifdef DEBUG
|
||||
if (gNoisy)
|
||||
{
|
||||
printf("** reinsert left child node %p before right node %p\n",
|
||||
static_cast<void*>(mNewLeftNode.get()),
|
||||
static_cast<void*>(mExistingRightNode.get()));
|
||||
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
|
||||
}
|
||||
#endif
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ TEST_DIRS += ['tests']
|
||||
|
||||
MODULE = 'editor'
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'ChangeAttributeTxn.cpp',
|
||||
'ChangeCSSInlineStyleTxn.cpp',
|
||||
'CreateElementTxn.cpp',
|
||||
|
@ -112,10 +112,6 @@ class nsIOutputStream;
|
||||
class nsIParserService;
|
||||
class nsITransferable;
|
||||
|
||||
#ifdef NS_DEBUG_EDITOR
|
||||
static bool gNoisy = false;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "nsIDOMHTMLDocument.h" // for nsIDOMHTMLDocument
|
||||
#endif
|
||||
@ -779,10 +775,6 @@ nsEditor::SetTransactionManager(nsITransactionManager *aTxnManager)
|
||||
NS_IMETHODIMP
|
||||
nsEditor::Undo(uint32_t aCount)
|
||||
{
|
||||
#ifdef NS_DEBUG_EDITOR
|
||||
if (gNoisy) { printf("Editor::Undo ----------\n"); }
|
||||
#endif
|
||||
|
||||
ForceCompositionEnd();
|
||||
|
||||
bool hasTxnMgr, hasTransaction = false;
|
||||
@ -824,10 +816,6 @@ NS_IMETHODIMP nsEditor::CanUndo(bool *aIsEnabled, bool *aCanUndo)
|
||||
NS_IMETHODIMP
|
||||
nsEditor::Redo(uint32_t aCount)
|
||||
{
|
||||
#ifdef NS_DEBUG_EDITOR
|
||||
if (gNoisy) { printf("Editor::Redo ----------\n"); }
|
||||
#endif
|
||||
|
||||
bool hasTxnMgr, hasTransaction = false;
|
||||
CanRedo(&hasTxnMgr, &hasTransaction);
|
||||
NS_ENSURE_TRUE(hasTransaction, NS_OK);
|
||||
@ -2714,10 +2702,6 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode,
|
||||
nsIDOMNode* aNewLeftNode,
|
||||
nsIDOMNode* aParent)
|
||||
{
|
||||
#ifdef NS_DEBUG_EDITOR
|
||||
if (gNoisy) { printf("SplitNodeImpl: left=%p, right=%p, offset=%d\n", (void*)aNewLeftNode, (void*)aExistingRightNode, aOffset); }
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(((nullptr!=aExistingRightNode) &&
|
||||
(nullptr!=aNewLeftNode) &&
|
||||
(nullptr!=aParent)),
|
||||
|
@ -8,7 +8,7 @@ TEST_DIRS += ['tests']
|
||||
|
||||
MODULE = 'editor'
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsEditProperty.cpp',
|
||||
'nsHTMLAbsPosition.cpp',
|
||||
'nsHTMLAnonymousUtils.cpp',
|
||||
|
@ -8,7 +8,7 @@ TEST_DIRS += ['tests']
|
||||
|
||||
MODULE = 'editor'
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsInternetCiter.cpp',
|
||||
'nsPlaintextDataTransfer.cpp',
|
||||
'nsPlaintextEditor.cpp',
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
MODULE = 'txmgr'
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsTransactionItem.cpp',
|
||||
'nsTransactionList.cpp',
|
||||
'nsTransactionManager.cpp',
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
MODULE = 'txtsvc'
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'nsFilteredContentIterator.cpp',
|
||||
'nsTextServicesDocument.cpp',
|
||||
]
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
57451
|
||||
57454
|
||||
0/nm
|
||||
0th/pt
|
||||
1/n1
|
||||
@ -3828,11 +3828,13 @@ DOS/M
|
||||
DOT
|
||||
DP/SM
|
||||
DPT
|
||||
DRM
|
||||
DST
|
||||
DTP
|
||||
DUI
|
||||
DVD
|
||||
DVDs
|
||||
DVR/S
|
||||
DWI
|
||||
Dacca/M
|
||||
Dacey/M
|
||||
@ -38880,6 +38882,7 @@ milky/RTP
|
||||
mill/MDRSZGJ
|
||||
millage/M
|
||||
millenarian
|
||||
millennia
|
||||
millennial
|
||||
millennium/SM
|
||||
millepede/MS
|
||||
|
@ -44,7 +44,8 @@ inline bool IsIgnorableCharacter(PRUnichar ch)
|
||||
inline bool IsConditionalPunctuation(PRUnichar ch)
|
||||
{
|
||||
return (ch == '\'' ||
|
||||
ch == 0x2019); // RIGHT SINGLE QUOTATION MARK
|
||||
ch == 0x2019 || // RIGHT SINGLE QUOTATION MARK
|
||||
ch == 0x00B7); // MIDDLE DOT
|
||||
}
|
||||
|
||||
// mozInlineSpellWordUtil::Init
|
||||
|
@ -345,7 +345,7 @@ PathD2D::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule)
|
||||
sink);
|
||||
}
|
||||
|
||||
RefPtr<PathBuilderD2D> pathBuilder = new PathBuilderD2D(sink, path, mFillRule);
|
||||
RefPtr<PathBuilderD2D> pathBuilder = new PathBuilderD2D(sink, path, aFillRule);
|
||||
|
||||
pathBuilder->mCurrentPoint = aTransform * mEndPoint;
|
||||
|
||||
|
@ -107,6 +107,8 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
bool aIsFirstPaint, uint64_t aFirstPaintLayersId,
|
||||
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy)
|
||||
{
|
||||
mTreeLock.AssertCurrentThreadOwns();
|
||||
|
||||
ContainerLayer* container = aLayer->AsContainerLayer();
|
||||
AsyncPanZoomController* apzc = nullptr;
|
||||
if (container) {
|
||||
@ -315,7 +317,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
|
||||
return result;
|
||||
}
|
||||
|
||||
AsyncPanZoomController*
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
|
||||
ScreenPoint aPoint)
|
||||
{
|
||||
@ -324,7 +326,7 @@ APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
|
||||
// Reset the cached apz transform
|
||||
mCachedTransformToApzcForInputBlock = transformToApzc;
|
||||
if (!apzc) {
|
||||
return nullptr;
|
||||
return apzc.forget();
|
||||
}
|
||||
for (size_t i = 1; i < aEvent.touches.Length(); i++) {
|
||||
nsIntPoint point = aEvent.touches[i]->mRefPoint;
|
||||
@ -341,7 +343,7 @@ APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
|
||||
// Cache apz transform so it can be used for future events in this block.
|
||||
GetInputTransforms(apzc, mCachedTransformToApzcForInputBlock, transformToGecko);
|
||||
}
|
||||
return apzc.get();
|
||||
return apzc.forget();
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
@ -349,6 +351,8 @@ APZCTreeManager::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
ScrollableLayerGuid* aOutTargetGuid,
|
||||
WidgetTouchEvent* aOutEvent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsEventStatus ret = nsEventStatus_eIgnore;
|
||||
if (!aEvent.touches.Length()) {
|
||||
return ret;
|
||||
@ -421,6 +425,8 @@ APZCTreeManager::ProcessMouseEvent(const WidgetMouseEvent& aEvent,
|
||||
ScrollableLayerGuid* aOutTargetGuid,
|
||||
WidgetMouseEvent* aOutEvent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y));
|
||||
if (!apzc) {
|
||||
return nsEventStatus_eIgnore;
|
||||
@ -441,6 +447,8 @@ APZCTreeManager::ProcessEvent(const WidgetInputEvent& aEvent,
|
||||
ScrollableLayerGuid* aOutTargetGuid,
|
||||
WidgetInputEvent* aOutEvent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Transform the refPoint
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y));
|
||||
if (!apzc) {
|
||||
@ -645,6 +653,8 @@ APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
|
||||
|
||||
AsyncPanZoomController*
|
||||
APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid) {
|
||||
mTreeLock.AssertCurrentThreadOwns();
|
||||
|
||||
// This walks the tree in depth-first, reverse order, so that it encounters
|
||||
// APZCs front-to-back on the screen.
|
||||
for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
|
||||
@ -663,6 +673,8 @@ APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableL
|
||||
AsyncPanZoomController*
|
||||
APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint)
|
||||
{
|
||||
mTreeLock.AssertCurrentThreadOwns();
|
||||
|
||||
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
|
||||
// explained in the comment on GetInputTransforms. This function will recurse with aApzc at L and P, and the
|
||||
// comments explain what values are stored in the variables at these two levels. All the comments
|
||||
@ -796,6 +808,8 @@ void
|
||||
APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
|
||||
gfx3DMatrix& aTransformToGeckoOut)
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
|
||||
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
|
||||
// explained in the comment above. This function is called with aApzc at L, and the loop
|
||||
// below performs one iteration, where parent is at P. The comments explain what values are stored
|
||||
@ -835,9 +849,12 @@ APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix&
|
||||
}
|
||||
}
|
||||
|
||||
AsyncPanZoomController*
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2)
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
nsRefPtr<AsyncPanZoomController> ancestor;
|
||||
|
||||
// If either aApzc1 or aApzc2 is null, min(depth1, depth2) will be 0 and this function
|
||||
// will return null.
|
||||
|
||||
@ -866,7 +883,8 @@ APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomCont
|
||||
// either APZC, and return the the first common ancestor encountered.
|
||||
while (true) {
|
||||
if (aApzc1 == aApzc2) {
|
||||
return aApzc1;
|
||||
ancestor = aApzc1;
|
||||
break;
|
||||
}
|
||||
if (depth1 <= 0) {
|
||||
break;
|
||||
@ -874,16 +892,18 @@ APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomCont
|
||||
aApzc1 = aApzc1->GetParent();
|
||||
aApzc2 = aApzc2->GetParent();
|
||||
}
|
||||
return nullptr;
|
||||
return ancestor.forget();
|
||||
}
|
||||
|
||||
AsyncPanZoomController*
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::RootAPZCForLayersId(AsyncPanZoomController* aApzc)
|
||||
{
|
||||
while (aApzc && !aApzc->IsRootForLayersId()) {
|
||||
aApzc = aApzc->GetParent();
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
nsRefPtr<AsyncPanZoomController> apzc = aApzc;
|
||||
while (apzc && !apzc->IsRootForLayersId()) {
|
||||
apzc = apzc->GetParent();
|
||||
}
|
||||
return aApzc;
|
||||
return apzc.forget();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -310,9 +310,9 @@ private:
|
||||
/* Helpers */
|
||||
AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
|
||||
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint);
|
||||
AsyncPanZoomController* CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
|
||||
AsyncPanZoomController* RootAPZCForLayersId(AsyncPanZoomController* aApzc);
|
||||
AsyncPanZoomController* GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent, ScreenPoint aPoint);
|
||||
already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
|
||||
already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
|
||||
already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent, ScreenPoint aPoint);
|
||||
nsEventStatus ProcessTouchEvent(const WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetTouchEvent* aOutEvent);
|
||||
nsEventStatus ProcessMouseEvent(const WidgetMouseEvent& mouseEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetMouseEvent* aOutEvent);
|
||||
nsEventStatus ProcessEvent(const WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetInputEvent* aOutEvent);
|
||||
|
1
gfx/tests/crashtests/624198.xhtml
Normal file
1
gfx/tests/crashtests/624198.xhtml
Normal 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>
|
@ -85,6 +85,7 @@ load 580233-1.html
|
||||
load 580719-1.html
|
||||
load 594654-1.xhtml
|
||||
load 595727-1.html
|
||||
load 624198.xhtml
|
||||
load 633453-1.html
|
||||
load 633322-1.html
|
||||
load 665218.html
|
||||
|
@ -3344,11 +3344,14 @@ gfxFont::ShapeTextWithoutWordCache(gfxContext *aContext,
|
||||
}
|
||||
|
||||
// fragment was terminated by an invalid char: skip it,
|
||||
// unless it's a control char that we want to show as a hexbox,
|
||||
// but record where TAB or NEWLINE occur
|
||||
if (ch == '\t') {
|
||||
aTextRun->SetIsTab(aOffset + i);
|
||||
} else if (ch == '\n') {
|
||||
aTextRun->SetIsNewline(aOffset + i);
|
||||
} else if ((ch & 0x7f) < 0x20 || ch == 0x7f) {
|
||||
aTextRun->SetMissingGlyph(aOffset + i, ch, this);
|
||||
}
|
||||
fragStart = i + 1;
|
||||
}
|
||||
@ -3485,11 +3488,14 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
|
||||
"how did we get here except via an invalid char?");
|
||||
|
||||
// word was terminated by an invalid char: skip it,
|
||||
// unless it's a control char that we want to show as a hexbox,
|
||||
// but record where TAB or NEWLINE occur
|
||||
if (ch == '\t') {
|
||||
aTextRun->SetIsTab(aRunStart + i);
|
||||
} else if (ch == '\n') {
|
||||
aTextRun->SetIsNewline(aRunStart + i);
|
||||
} else if ((ch & 0x7f) < 0x20 || ch == 0x7f) {
|
||||
aTextRun->SetMissingGlyph(aRunStart + i, ch, this);
|
||||
}
|
||||
|
||||
hash = 0;
|
||||
|
@ -1602,33 +1602,51 @@ class MutableValueOperations : public UnbarrieredMutableValueOperations<Outer>
|
||||
* type-querying, value-extracting, and mutating operations.
|
||||
*/
|
||||
template <>
|
||||
class HeapBase<JS::Value> : public UnbarrieredMutableValueOperations<JS::Heap<JS::Value> >
|
||||
class HeapBase<JS::Value> : public ValueOperations<JS::Heap<JS::Value> >
|
||||
{
|
||||
typedef JS::Heap<JS::Value> Outer;
|
||||
|
||||
friend class ValueOperations<Outer>;
|
||||
friend class UnbarrieredMutableValueOperations<Outer>;
|
||||
|
||||
const JS::Value * extract() const { return static_cast<const Outer*>(this)->address(); }
|
||||
JS::Value * extractMutable() { return static_cast<Outer*>(this)->unsafeGet(); }
|
||||
|
||||
/*
|
||||
* Setters that potentially change the value to a GC thing from a non-GC
|
||||
* thing must call JS::Heap::set() to trigger the post barrier.
|
||||
*
|
||||
* Changing from a GC thing to a non-GC thing value will leave the heap
|
||||
* value in the store buffer, but it will be ingored so this is not a
|
||||
* problem.
|
||||
*/
|
||||
void setBarriered(const JS::Value &v) {
|
||||
static_cast<JS::Heap<JS::Value> *>(this)->set(v);
|
||||
}
|
||||
|
||||
public:
|
||||
void setNull() { setBarriered(JS::NullValue()); }
|
||||
void setUndefined() { setBarriered(JS::UndefinedValue()); }
|
||||
void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); }
|
||||
void setDouble(double d) { setBarriered(JS::DoubleValue(d)); }
|
||||
void setNaN() { setDouble(JS::GenericNaN()); }
|
||||
void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); }
|
||||
void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); }
|
||||
void setString(JSString *str) { setBarriered(JS::StringValue(str)); }
|
||||
void setString(const JS::Anchor<JSString *> &str) { setBarriered(JS::StringValue(str.get())); }
|
||||
void setObject(JSObject &obj) { setBarriered(JS::ObjectValue(obj)); }
|
||||
|
||||
bool setNumber(uint32_t ui) {
|
||||
if (ui > JSVAL_INT_MAX) {
|
||||
setDouble((double)ui);
|
||||
return false;
|
||||
} else {
|
||||
setInt32((int32_t)ui);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool setNumber(double d) {
|
||||
int32_t i;
|
||||
if (mozilla::DoubleIsInt32(d, &i)) {
|
||||
setInt32(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
setDouble(d);
|
||||
return false;
|
||||
}
|
||||
|
||||
void setObjectOrNull(JSObject *arg) {
|
||||
if (arg)
|
||||
setObject(*arg);
|
||||
|
@ -16,6 +16,8 @@ MacroAssemblerX86Common::SSECheckState MacroAssemblerX86Common::s_sseCheckState
|
||||
|
||||
#ifdef DEBUG
|
||||
bool MacroAssemblerX86Common::s_floatingPointDisabled = false;
|
||||
bool MacroAssemblerX86Common::s_SSE3Disabled = false;
|
||||
bool MacroAssemblerX86Common::s_SSE4Disabled = false;
|
||||
#endif
|
||||
|
||||
#endif /* WTF_CPU_X86 || WTF_CPU_X86_64 */
|
||||
|
@ -1403,6 +1403,13 @@ private:
|
||||
s_sseCheckState = HasSSE;
|
||||
else
|
||||
s_sseCheckState = NoSSE;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (s_sseCheckState >= HasSSE4_1 && s_SSE4Disabled)
|
||||
s_sseCheckState = HasSSE3;
|
||||
if (s_sseCheckState >= HasSSE3 && s_SSE3Disabled)
|
||||
s_sseCheckState = HasSSE2;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if WTF_CPU_X86
|
||||
@ -1505,11 +1512,19 @@ private:
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool s_floatingPointDisabled;
|
||||
static bool s_SSE3Disabled;
|
||||
static bool s_SSE4Disabled;
|
||||
|
||||
public:
|
||||
static void SetFloatingPointDisabled() {
|
||||
s_floatingPointDisabled = true;
|
||||
}
|
||||
static void SetSSE3Disabled() {
|
||||
s_SSE3Disabled = true;
|
||||
}
|
||||
static void SetSSE4Disabled() {
|
||||
s_SSE4Disabled = true;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -529,6 +529,7 @@ const JSPropertySpec ArrayType::typedObjectProperties[] = {
|
||||
const JSFunctionSpec ArrayType::typedObjectMethods[] = {
|
||||
JS_FN("subarray", ArrayType::subarray, 2, 0),
|
||||
{"forEach", {nullptr, nullptr}, 1, 0, "ArrayForEach"},
|
||||
{"redimension", {nullptr, nullptr}, 1, 0, "TypedArrayRedimension"},
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
@ -415,6 +415,73 @@ function TypeObjectEquivalent(otherTypeObj) {
|
||||
return TYPE_TYPE_REPR(this) === TYPE_TYPE_REPR(otherTypeObj);
|
||||
}
|
||||
|
||||
// TypedArray.redimension(newArrayType)
|
||||
//
|
||||
// Method that "repackages" the data from this array into a new typed
|
||||
// object whose type is `newArrayType`. Once you strip away all the
|
||||
// outer array dimensions, the type of `this` array and `newArrayType`
|
||||
// must share the same innermost element type. Moreover, those
|
||||
// stripped away dimensions must amount to the same total number of
|
||||
// elements.
|
||||
//
|
||||
// For example, given two equivalent types `T` and `U`, it is legal to
|
||||
// interconvert between arrays types like:
|
||||
// T[32]
|
||||
// U[2][16]
|
||||
// U[2][2][8]
|
||||
// Because they all share the same total number (32) of equivalent elements.
|
||||
// But it would be illegal to convert `T[32]` to `U[31]` or `U[2][17]`, since
|
||||
// the number of elements differs. And it's just plain incompatible to convert
|
||||
// if the base element types are not equivalent.
|
||||
//
|
||||
// Warning: user exposed!
|
||||
function TypedArrayRedimension(newArrayType) {
|
||||
if (!IsObject(this) || !ObjectIsTypedDatum(this))
|
||||
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
|
||||
|
||||
if (!IsObject(newArrayType) || !ObjectIsTypeObject(newArrayType))
|
||||
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1, "type object");
|
||||
|
||||
// Peel away the outermost array layers from the type of `this` to find
|
||||
// the core element type. In the process, count the number of elements.
|
||||
var oldArrayType = DATUM_TYPE_OBJ(this);
|
||||
var oldElementType = oldArrayType;
|
||||
var oldElementCount = 1;
|
||||
while (REPR_KIND(TYPE_TYPE_REPR(oldElementType)) == JS_TYPEREPR_ARRAY_KIND) {
|
||||
oldElementCount *= oldElementType.length;
|
||||
oldElementType = oldElementType.elementType;
|
||||
}
|
||||
|
||||
// Peel away the outermost array layers from `newArrayType`. In the
|
||||
// process, count the number of elements.
|
||||
var newElementType = newArrayType;
|
||||
var newElementCount = 1;
|
||||
while (REPR_KIND(TYPE_TYPE_REPR(newElementType)) == JS_TYPEREPR_ARRAY_KIND) {
|
||||
newElementCount *= newElementType.length;
|
||||
newElementType = newElementType.elementType;
|
||||
}
|
||||
|
||||
// Check that the total number of elements does not change.
|
||||
if (oldElementCount !== newElementCount) {
|
||||
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1,
|
||||
"New number of elements does not match old number of elements");
|
||||
}
|
||||
|
||||
// Check that the element types are equivalent.
|
||||
if (TYPE_TYPE_REPR(oldElementType) !== TYPE_TYPE_REPR(newElementType)) {
|
||||
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1,
|
||||
"New element type is not equivalent to old element type");
|
||||
}
|
||||
|
||||
// Together, this should imply that the sizes are unchanged.
|
||||
assert(REPR_SIZE(TYPE_TYPE_REPR(oldArrayType)) ==
|
||||
REPR_SIZE(TYPE_TYPE_REPR(newArrayType)),
|
||||
"Byte sizes should be equal");
|
||||
|
||||
// Rewrap the data from `this` in a new type.
|
||||
return NewDerivedTypedDatum(newArrayType, this, 0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Handles
|
||||
//
|
||||
|
@ -800,7 +800,7 @@ else # !WINNT || GNU_CC
|
||||
endif # WINNT && !GNU_CC
|
||||
|
||||
ifdef ENABLE_STRIP
|
||||
$(STRIP) $@
|
||||
$(STRIP) $(STRIP_FLAGS) $@
|
||||
endif
|
||||
ifdef MOZ_POST_PROGRAM_COMMAND
|
||||
$(MOZ_POST_PROGRAM_COMMAND) $@
|
||||
@ -856,7 +856,7 @@ else
|
||||
endif # WINNT && !GNU_CC
|
||||
|
||||
ifdef ENABLE_STRIP
|
||||
$(STRIP) $@
|
||||
$(STRIP) $(STRIP_FLAGS) $@
|
||||
endif
|
||||
ifdef MOZ_POST_PROGRAM_COMMAND
|
||||
$(MOZ_POST_PROGRAM_COMMAND) $@
|
||||
@ -883,7 +883,6 @@ $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
|
||||
$(REPORT_BUILD)
|
||||
$(RM) $(LIBRARY)
|
||||
$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(SHARED_LIBRARY_LIBS)
|
||||
$(RANLIB) $@
|
||||
|
||||
$(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
|
||||
# When we only build a library descriptor, blow out any existing library
|
||||
@ -917,14 +916,12 @@ $(IMPORT_LIBRARY): $(SHARED_LIBRARY)
|
||||
$(REPORT_BUILD)
|
||||
$(RM) $@
|
||||
$(IMPLIB) $@ $^
|
||||
$(RANLIB) $@
|
||||
endif # OS/2
|
||||
|
||||
$(HOST_LIBRARY): $(HOST_OBJS) Makefile
|
||||
$(REPORT_BUILD)
|
||||
$(RM) $@
|
||||
$(EXPAND_LIBS_EXEC) --extract -- $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
|
||||
$(HOST_RANLIB) $@
|
||||
|
||||
ifdef HAVE_DTRACE
|
||||
ifndef XP_MACOSX
|
||||
@ -975,7 +972,7 @@ endif # WINNT && !GCC
|
||||
@$(RM) foodummyfilefoo $(DELETE_AFTER_LINK)
|
||||
chmod +x $@
|
||||
ifdef ENABLE_STRIP
|
||||
$(STRIP) $@
|
||||
$(STRIP) $(STRIP_FLAGS) $@
|
||||
endif
|
||||
ifdef MOZ_POST_DSO_LIB_COMMAND
|
||||
$(MOZ_POST_DSO_LIB_COMMAND) $@
|
||||
|
@ -284,7 +284,7 @@ dnl to use the cross-compile setup for now
|
||||
dnl ========================================================
|
||||
|
||||
dnl AR_FLAGS set here so HOST_AR_FLAGS can be set correctly (see bug 538269)
|
||||
AR_FLAGS='cr $@'
|
||||
AR_FLAGS='crs $@'
|
||||
|
||||
if test "$COMPILE_ENVIRONMENT"; then
|
||||
|
||||
|
@ -59,6 +59,7 @@ struct frontend::StmtInfoBCE : public StmtInfoBase
|
||||
ptrdiff_t update; /* loop update offset (top if none) */
|
||||
ptrdiff_t breaks; /* offset of last break in loop */
|
||||
ptrdiff_t continues; /* offset of last continue in loop */
|
||||
uint32_t blockScopeIndex; /* index of scope in BlockScopeArray */
|
||||
|
||||
StmtInfoBCE(ExclusiveContext *cx) : StmtInfoBase(cx) {}
|
||||
|
||||
@ -100,10 +101,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
|
||||
atomIndices(sc->context),
|
||||
firstLine(lineNum),
|
||||
stackDepth(0), maxStackDepth(0),
|
||||
tryNoteList(sc->context),
|
||||
arrayCompDepth(0),
|
||||
emitLevel(0),
|
||||
constList(sc->context),
|
||||
tryNoteList(sc->context),
|
||||
blockScopeList(sc->context),
|
||||
typesetCount(0),
|
||||
hasSingletons(false),
|
||||
emittingForInit(false),
|
||||
@ -686,13 +688,23 @@ EnclosingStaticScope(BytecodeEmitter *bce)
|
||||
}
|
||||
|
||||
// Push a block scope statement and link blockObj into bce->blockChain.
|
||||
static void
|
||||
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StaticBlockObject &blockObj,
|
||||
static bool
|
||||
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
|
||||
ptrdiff_t top)
|
||||
{
|
||||
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
|
||||
|
||||
PushStatementBCE(bce, stmt, STMT_BLOCK, top);
|
||||
|
||||
unsigned scopeObjectIndex = bce->objectList.add(objbox);
|
||||
stmt->blockScopeIndex = bce->blockScopeList.length();
|
||||
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset()))
|
||||
return false;
|
||||
|
||||
blockObj.initEnclosingStaticScope(EnclosingStaticScope(bce));
|
||||
FinishPushBlockScope(bce, stmt, blockObj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Patches |breaks| and |continues| unless the top statement info record
|
||||
@ -707,6 +719,10 @@ PopStatementBCE(ExclusiveContext *cx, BytecodeEmitter *bce)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stmt->isBlockScope)
|
||||
bce->blockScopeList.recordEnd(stmt->blockScopeIndex, bce->offset());
|
||||
|
||||
FinishPopStatement(bce);
|
||||
return true;
|
||||
}
|
||||
@ -770,10 +786,17 @@ EmitAtomOp(ExclusiveContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitObjectOp(ExclusiveContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
|
||||
EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmitter *bce)
|
||||
{
|
||||
JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
|
||||
return EmitIndex32(cx, op, bce->objectList.add(objbox), bce);
|
||||
JS_ASSERT(index < bce->objectList.length);
|
||||
return EmitIndex32(cx, op, index, bce);
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitObjectOp(ExclusiveContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
|
||||
{
|
||||
return EmitInternedObjectOp(cx, bce->objectList.add(objbox), op, bce);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1061,7 +1084,15 @@ static bool
|
||||
EmitEnterBlock(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
|
||||
{
|
||||
JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
|
||||
if (!EmitObjectOp(cx, pn->pn_objbox, op, bce))
|
||||
StmtInfoBCE *stmt = bce->topStmt;
|
||||
JS_ASSERT(stmt->type == STMT_BLOCK || stmt->type == STMT_SWITCH);
|
||||
JS_ASSERT(stmt->isBlockScope);
|
||||
JS_ASSERT(stmt->blockScopeIndex == bce->blockScopeList.length() - 1);
|
||||
JS_ASSERT(bce->blockScopeList.list[stmt->blockScopeIndex].length == 0);
|
||||
uint32_t scopeObjectIndex = bce->blockScopeList.list[stmt->blockScopeIndex].index;
|
||||
JS_ASSERT(scopeObjectIndex == bce->objectList.length - 1);
|
||||
JS_ASSERT(pn->pn_objbox == bce->objectList.lastbox);
|
||||
if (!EmitInternedObjectOp(cx, scopeObjectIndex, op, bce))
|
||||
return false;
|
||||
|
||||
Rooted<StaticBlockObject*> blockObj(cx, &pn->pn_objbox->object->as<StaticBlockObject>());
|
||||
@ -2305,7 +2336,8 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
return false;
|
||||
|
||||
if (pn2->isKind(PNK_LEXICALSCOPE)) {
|
||||
PushBlockScopeBCE(bce, &stmtInfo, pn2->pn_objbox->object->as<StaticBlockObject>(), -1);
|
||||
if (!PushBlockScopeBCE(bce, &stmtInfo, pn2->pn_objbox, -1))
|
||||
return false;
|
||||
stmtInfo.type = STMT_SWITCH;
|
||||
if (!EmitEnterBlock(cx, bce, pn2, JSOP_ENTERLET1))
|
||||
return false;
|
||||
@ -4193,7 +4225,8 @@ EmitLet(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
|
||||
}
|
||||
|
||||
StmtInfoBCE stmtInfo(cx);
|
||||
PushBlockScopeBCE(bce, &stmtInfo, *blockObj, bce->offset());
|
||||
if (!PushBlockScopeBCE(bce, &stmtInfo, letBody->pn_objbox, bce->offset()))
|
||||
return false;
|
||||
|
||||
DebugOnly<ptrdiff_t> bodyBegin = bce->offset();
|
||||
if (!EmitEnterBlock(cx, bce, letBody, JSOP_ENTERLET0))
|
||||
@ -4226,7 +4259,8 @@ EmitLexicalScope(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
ObjectBox *objbox = pn->pn_objbox;
|
||||
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
|
||||
size_t slots = blockObj.slotCount();
|
||||
PushBlockScopeBCE(bce, &stmtInfo, blockObj, bce->offset());
|
||||
if (!PushBlockScopeBCE(bce, &stmtInfo, objbox, bce->offset()))
|
||||
return false;
|
||||
|
||||
if (!EmitEnterBlock(cx, bce, pn, JSOP_ENTERBLOCK))
|
||||
return false;
|
||||
@ -4316,7 +4350,8 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
// Enter the block before the loop body, after evaluating the obj.
|
||||
StmtInfoBCE letStmt(cx);
|
||||
if (letDecl) {
|
||||
PushBlockScopeBCE(bce, &letStmt, *blockObj, bce->offset());
|
||||
if (!PushBlockScopeBCE(bce, &letStmt, pn1->pn_objbox, bce->offset()))
|
||||
return false;
|
||||
letStmt.isForLetBlock = true;
|
||||
if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET2))
|
||||
return false;
|
||||
@ -4492,7 +4527,8 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
/* Enter the block before the loop body, after evaluating the obj. */
|
||||
StmtInfoBCE letStmt(cx);
|
||||
if (letDecl) {
|
||||
PushBlockScopeBCE(bce, &letStmt, *blockObj, bce->offset());
|
||||
if (!PushBlockScopeBCE(bce, &letStmt, pn1->pn_objbox, bce->offset()))
|
||||
return false;
|
||||
letStmt.isForLetBlock = true;
|
||||
if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1))
|
||||
return false;
|
||||
@ -6775,25 +6811,8 @@ frontend::FinishTakingSrcNotes(ExclusiveContext *cx, BytecodeEmitter *bce, jssrc
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CGTryNoteList::append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end)
|
||||
{
|
||||
JS_ASSERT(unsigned(uint16_t(stackDepth)) == stackDepth);
|
||||
JS_ASSERT(start <= end);
|
||||
JS_ASSERT(size_t(uint32_t(start)) == start);
|
||||
JS_ASSERT(size_t(uint32_t(end)) == end);
|
||||
|
||||
JSTryNote note;
|
||||
note.kind = kind;
|
||||
note.stackDepth = uint16_t(stackDepth);
|
||||
note.start = uint32_t(start);
|
||||
note.length = uint32_t(end - start);
|
||||
|
||||
return list.append(note);
|
||||
}
|
||||
|
||||
void
|
||||
CGTryNoteList::finish(TryNoteArray *array)
|
||||
CGConstList::finish(ConstArray *array)
|
||||
{
|
||||
JS_ASSERT(length() == array->length);
|
||||
|
||||
@ -6878,8 +6897,56 @@ CGObjectList::finish(ObjectArray *array)
|
||||
JS_ASSERT(cursor == array->vector);
|
||||
}
|
||||
|
||||
bool
|
||||
CGTryNoteList::append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end)
|
||||
{
|
||||
JS_ASSERT(unsigned(uint16_t(stackDepth)) == stackDepth);
|
||||
JS_ASSERT(start <= end);
|
||||
JS_ASSERT(size_t(uint32_t(start)) == start);
|
||||
JS_ASSERT(size_t(uint32_t(end)) == end);
|
||||
|
||||
JSTryNote note;
|
||||
note.kind = kind;
|
||||
note.stackDepth = uint16_t(stackDepth);
|
||||
note.start = uint32_t(start);
|
||||
note.length = uint32_t(end - start);
|
||||
|
||||
return list.append(note);
|
||||
}
|
||||
|
||||
void
|
||||
CGConstList::finish(ConstArray *array)
|
||||
CGTryNoteList::finish(TryNoteArray *array)
|
||||
{
|
||||
JS_ASSERT(length() == array->length);
|
||||
|
||||
for (unsigned i = 0; i < length(); i++)
|
||||
array->vector[i] = list[i];
|
||||
}
|
||||
|
||||
bool
|
||||
CGBlockScopeList::append(uint32_t scopeObject, uint32_t offset)
|
||||
{
|
||||
BlockScopeNote note;
|
||||
mozilla::PodZero(¬e);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -28,13 +28,13 @@ template <typename ParseHandler> class Parser;
|
||||
class SharedContext;
|
||||
class TokenStream;
|
||||
|
||||
struct CGTryNoteList {
|
||||
Vector<JSTryNote> list;
|
||||
CGTryNoteList(ExclusiveContext *cx) : list(cx) {}
|
||||
|
||||
bool append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end);
|
||||
class CGConstList {
|
||||
Vector<Value> list;
|
||||
public:
|
||||
CGConstList(ExclusiveContext *cx) : list(cx) {}
|
||||
bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
|
||||
size_t length() const { return list.length(); }
|
||||
void finish(TryNoteArray *array);
|
||||
void finish(ConstArray *array);
|
||||
};
|
||||
|
||||
struct CGObjectList {
|
||||
@ -48,13 +48,23 @@ struct CGObjectList {
|
||||
void finish(ObjectArray *array);
|
||||
};
|
||||
|
||||
class CGConstList {
|
||||
Vector<Value> list;
|
||||
public:
|
||||
CGConstList(ExclusiveContext *cx) : list(cx) {}
|
||||
bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
|
||||
struct CGTryNoteList {
|
||||
Vector<JSTryNote> list;
|
||||
CGTryNoteList(ExclusiveContext *cx) : list(cx) {}
|
||||
|
||||
bool append(JSTryNoteKind kind, unsigned stackDepth, size_t start, size_t end);
|
||||
size_t length() const { return list.length(); }
|
||||
void finish(ConstArray *array);
|
||||
void finish(TryNoteArray *array);
|
||||
};
|
||||
|
||||
struct CGBlockScopeList {
|
||||
Vector<BlockScopeNote> list;
|
||||
CGBlockScopeList(ExclusiveContext *cx) : list(cx) {}
|
||||
|
||||
bool append(uint32_t scopeObject, uint32_t offset);
|
||||
void recordEnd(uint32_t index, uint32_t offset);
|
||||
size_t length() const { return list.length(); }
|
||||
void finish(BlockScopeArray *array);
|
||||
};
|
||||
|
||||
struct StmtInfoBCE;
|
||||
@ -104,8 +114,6 @@ struct BytecodeEmitter
|
||||
int stackDepth; /* current stack depth in script frame */
|
||||
unsigned maxStackDepth; /* maximum stack depth so far */
|
||||
|
||||
CGTryNoteList tryNoteList; /* list of emitted try notes */
|
||||
|
||||
unsigned arrayCompDepth; /* stack depth of array in comprehension */
|
||||
|
||||
unsigned emitLevel; /* js::frontend::EmitTree recursion level */
|
||||
@ -115,6 +123,8 @@ struct BytecodeEmitter
|
||||
CGObjectList objectList; /* list of emitted objects */
|
||||
CGObjectList regexpList; /* list of emitted regexp that will be
|
||||
cloned during execution */
|
||||
CGTryNoteList tryNoteList; /* list of emitted try notes */
|
||||
CGBlockScopeList blockScopeList;/* list of emitted block scope notes */
|
||||
|
||||
uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */
|
||||
|
||||
|
@ -164,7 +164,7 @@ def main(argv):
|
||||
flags = [
|
||||
[], # no flags, normal baseline and ion
|
||||
['--ion-eager'], # implies --baseline-eager
|
||||
['--ion-eager', '--ion-check-range-analysis'],
|
||||
['--ion-eager', '--ion-check-range-analysis', '--no-sse3'],
|
||||
['--baseline-eager'],
|
||||
['--baseline-eager', '--no-ti', '--no-fpu'],
|
||||
['--no-baseline', '--no-ion'],
|
||||
|
@ -1,6 +1,18 @@
|
||||
(function() {
|
||||
"use asm"
|
||||
"use asm";
|
||||
function f() {
|
||||
i((1.5 != 2.) ? 3 : 0)
|
||||
i((1.5 != 2.) ? 3 : 0);
|
||||
}
|
||||
return f;
|
||||
})();
|
||||
|
||||
// Bug 933104
|
||||
(function() {
|
||||
"use asm";
|
||||
function f(x) {
|
||||
x = +x;
|
||||
x = -2.;
|
||||
(x > -1.5) ? 0 : 0;
|
||||
}
|
||||
return f;
|
||||
})()
|
||||
|
@ -1,3 +1,5 @@
|
||||
if (typeof ParallelArray === "undefined")
|
||||
quit();
|
||||
|
||||
x = ParallelArray([1942], function() {})
|
||||
x + watch.call(x, "length", (function() {}));
|
||||
|
@ -113,12 +113,12 @@ BacktrackingAllocator::go()
|
||||
return false;
|
||||
IonSpew(IonSpew_RegAlloc, "Liveness analysis complete");
|
||||
|
||||
if (IonSpewEnabled(IonSpew_RegAlloc))
|
||||
dumpLiveness();
|
||||
|
||||
if (!init())
|
||||
return false;
|
||||
|
||||
if (IonSpewEnabled(IonSpew_RegAlloc))
|
||||
dumpLiveness();
|
||||
|
||||
if (!allocationQueue.reserve(graph.numVirtualRegisters() * 3 / 2))
|
||||
return false;
|
||||
|
||||
@ -317,7 +317,9 @@ BacktrackingAllocator::tryGroupReusedRegister(uint32_t def, uint32_t use)
|
||||
if (!newIntervals.append(preInterval) || !newIntervals.append(postInterval))
|
||||
return false;
|
||||
|
||||
if (!distributeUses(interval, newIntervals) || !split(interval, newIntervals))
|
||||
distributeUses(interval, newIntervals);
|
||||
|
||||
if (!split(interval, newIntervals))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(usedReg.numIntervals() == 2);
|
||||
@ -331,7 +333,9 @@ bool
|
||||
BacktrackingAllocator::groupAndQueueRegisters()
|
||||
{
|
||||
// Try to group registers with their reused inputs.
|
||||
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
|
||||
// Virtual register number 0 is unused.
|
||||
JS_ASSERT(vregs[0u].numIntervals() == 0);
|
||||
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
|
||||
BacktrackingVirtualRegister ® = vregs[i];
|
||||
if (!reg.numIntervals())
|
||||
continue;
|
||||
@ -357,7 +361,9 @@ BacktrackingAllocator::groupAndQueueRegisters()
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
|
||||
// Virtual register number 0 is unused.
|
||||
JS_ASSERT(vregs[0u].numIntervals() == 0);
|
||||
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
|
||||
if (mir->shouldCancel("Backtracking Enqueue Registers"))
|
||||
return false;
|
||||
|
||||
@ -491,19 +497,17 @@ BacktrackingAllocator::processInterval(LiveInterval *interval)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to allocate a register for this interval.
|
||||
|
||||
if (attempt < MAX_ATTEMPTS &&
|
||||
canAllocate &&
|
||||
!fixed &&
|
||||
conflict &&
|
||||
computeSpillWeight(conflict) < computeSpillWeight(interval))
|
||||
{
|
||||
if (!evictInterval(conflict))
|
||||
return false;
|
||||
continue;
|
||||
// Failed to allocate a register for this interval.
|
||||
if (attempt < MAX_ATTEMPTS &&
|
||||
!fixed &&
|
||||
conflict &&
|
||||
computeSpillWeight(conflict) < computeSpillWeight(interval))
|
||||
{
|
||||
if (!evictInterval(conflict))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// A minimal interval cannot be split any further. If we try to split
|
||||
@ -757,7 +761,7 @@ BacktrackingAllocator::evictInterval(LiveInterval *interval)
|
||||
return allocationQueue.insert(QueueItem(interval, priority));
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
BacktrackingAllocator::distributeUses(LiveInterval *interval,
|
||||
const LiveIntervalVector &newIntervals)
|
||||
{
|
||||
@ -782,8 +786,6 @@ BacktrackingAllocator::distributeUses(LiveInterval *interval,
|
||||
}
|
||||
addInterval->addUse(new UsePosition(iter->use, iter->pos));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -791,7 +793,7 @@ BacktrackingAllocator::split(LiveInterval *interval,
|
||||
const LiveIntervalVector &newIntervals)
|
||||
{
|
||||
if (IonSpewEnabled(IonSpew_RegAlloc)) {
|
||||
IonSpew(IonSpew_RegAlloc, "splitting interval v%u %s:",
|
||||
IonSpew(IonSpew_RegAlloc, "splitting interval v%u %s into:",
|
||||
interval->vreg(), IntervalString(interval));
|
||||
for (size_t i = 0; i < newIntervals.length(); i++)
|
||||
IonSpew(IonSpew_RegAlloc, " %s", IntervalString(newIntervals[i]));
|
||||
@ -885,7 +887,9 @@ BacktrackingAllocator::spill(LiveInterval *interval)
|
||||
bool
|
||||
BacktrackingAllocator::resolveControlFlow()
|
||||
{
|
||||
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
|
||||
// Virtual register number 0 is unused.
|
||||
JS_ASSERT(vregs[0u].numIntervals() == 0);
|
||||
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
|
||||
BacktrackingVirtualRegister *reg = &vregs[i];
|
||||
|
||||
if (mir->shouldCancel("Backtracking Resolve Control Flow (vreg loop)"))
|
||||
@ -1001,11 +1005,11 @@ BacktrackingAllocator::isReusedInput(LUse *use, LInstruction *ins, bool consider
|
||||
}
|
||||
|
||||
bool
|
||||
BacktrackingAllocator::isRegisterUse(LUse *use, LInstruction *ins)
|
||||
BacktrackingAllocator::isRegisterUse(LUse *use, LInstruction *ins, bool considerCopy)
|
||||
{
|
||||
switch (use->policy()) {
|
||||
case LUse::ANY:
|
||||
return isReusedInput(use, ins);
|
||||
return isReusedInput(use, ins, considerCopy);
|
||||
|
||||
case LUse::REGISTER:
|
||||
case LUse::FIXED:
|
||||
@ -1035,7 +1039,9 @@ BacktrackingAllocator::isRegisterDefinition(LiveInterval *interval)
|
||||
bool
|
||||
BacktrackingAllocator::reifyAllocations()
|
||||
{
|
||||
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
|
||||
// Virtual register number 0 is unused.
|
||||
JS_ASSERT(vregs[0u].numIntervals() == 0);
|
||||
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
|
||||
VirtualRegister *reg = &vregs[i];
|
||||
|
||||
if (mir->shouldCancel("Backtracking Reify Allocations (main loop)"))
|
||||
@ -1095,7 +1101,9 @@ BacktrackingAllocator::populateSafepoints()
|
||||
{
|
||||
size_t firstSafepoint = 0;
|
||||
|
||||
for (uint32_t i = 0; i < vregs.numVirtualRegisters(); i++) {
|
||||
// Virtual register number 0 is unused.
|
||||
JS_ASSERT(!vregs[0u].def());
|
||||
for (uint32_t i = 1; i < vregs.numVirtualRegisters(); i++) {
|
||||
BacktrackingVirtualRegister *reg = &vregs[i];
|
||||
|
||||
if (!reg->def() || (!IsTraceable(reg) && !IsSlotsOrElements(reg) && !IsNunbox(reg)))
|
||||
@ -1132,7 +1140,7 @@ BacktrackingAllocator::populateSafepoints()
|
||||
|
||||
for (size_t k = 0; k < reg->numIntervals(); k++) {
|
||||
LiveInterval *interval = reg->getInterval(k);
|
||||
if (!interval->covers(inputOf(ins)))
|
||||
if (!interval->covers(outputOf(ins)))
|
||||
continue;
|
||||
|
||||
LAllocation *a = interval->getAllocation();
|
||||
@ -1172,7 +1180,10 @@ void
|
||||
BacktrackingAllocator::dumpRegisterGroups()
|
||||
{
|
||||
fprintf(stderr, "Register groups:\n");
|
||||
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
|
||||
|
||||
// Virtual register number 0 is unused.
|
||||
JS_ASSERT(!vregs[0u].group());
|
||||
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
|
||||
VirtualRegisterGroup *group = vregs[i].group();
|
||||
if (group && i == group->canonicalReg()) {
|
||||
for (size_t j = 0; j < group->registers.length(); j++)
|
||||
@ -1200,11 +1211,12 @@ BacktrackingAllocator::dumpLiveness()
|
||||
for (size_t i = 0; i < block->numPhis(); i++) {
|
||||
LPhi *phi = block->getPhi(i);
|
||||
|
||||
fprintf(stderr, "[%u,%u Phi v%u <-",
|
||||
inputOf(phi).pos(), outputOf(phi).pos(),
|
||||
// Don't print the inputOf for phi nodes, since it's never used.
|
||||
fprintf(stderr, "[,%u Phi [def v%u] <-",
|
||||
outputOf(phi).pos(),
|
||||
phi->getDef(0)->virtualRegister());
|
||||
for (size_t j = 0; j < phi->numOperands(); j++)
|
||||
fprintf(stderr, " v%u", phi->getOperand(j)->toUse()->virtualRegister());
|
||||
fprintf(stderr, " %s", phi->getOperand(j)->toString());
|
||||
fprintf(stderr, "]\n");
|
||||
}
|
||||
|
||||
@ -1224,10 +1236,8 @@ BacktrackingAllocator::dumpLiveness()
|
||||
fprintf(stderr, " [def v%u]", def->virtualRegister());
|
||||
}
|
||||
|
||||
for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next()) {
|
||||
if (alloc->isUse())
|
||||
fprintf(stderr, " [use v%u]", alloc->toUse()->virtualRegister());
|
||||
}
|
||||
for (LInstruction::InputIterator alloc(*ins); alloc.more(); alloc.next())
|
||||
fprintf(stderr, " [use %s]", alloc->toString());
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
@ -1236,9 +1246,12 @@ BacktrackingAllocator::dumpLiveness()
|
||||
fprintf(stderr, "\nLive Ranges:\n\n");
|
||||
|
||||
for (size_t i = 0; i < AnyRegister::Total; i++)
|
||||
fprintf(stderr, "reg %s: %s\n", AnyRegister::FromCode(i).name(), IntervalString(fixedIntervals[i]));
|
||||
if (registers[i].allocatable)
|
||||
fprintf(stderr, "reg %s: %s\n", AnyRegister::FromCode(i).name(), IntervalString(fixedIntervals[i]));
|
||||
|
||||
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
|
||||
// Virtual register number 0 is unused.
|
||||
JS_ASSERT(vregs[0u].numIntervals() == 0);
|
||||
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
|
||||
fprintf(stderr, "v%lu:", static_cast<unsigned long>(i));
|
||||
VirtualRegister &vreg = vregs[i];
|
||||
for (size_t j = 0; j < vreg.numIntervals(); j++) {
|
||||
@ -1259,9 +1272,13 @@ struct BacktrackingAllocator::PrintLiveIntervalRange
|
||||
void operator()(const AllocatedRange &item)
|
||||
{
|
||||
if (item.range == item.interval->getRange(0)) {
|
||||
fprintf(stderr, " v%u: %s\n",
|
||||
item.interval->hasVreg() ? item.interval->vreg() : 0,
|
||||
IntervalString(item.interval));
|
||||
if (item.interval->hasVreg())
|
||||
fprintf(stderr, " v%u: %s\n",
|
||||
item.interval->vreg(),
|
||||
IntervalString(item.interval));
|
||||
else
|
||||
fprintf(stderr, " fixed: %s\n",
|
||||
IntervalString(item.interval));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1273,7 +1290,9 @@ BacktrackingAllocator::dumpAllocations()
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Allocations:\n");
|
||||
|
||||
for (size_t i = 0; i < graph.numVirtualRegisters(); i++) {
|
||||
// Virtual register number 0 is unused.
|
||||
JS_ASSERT(vregs[0u].numIntervals() == 0);
|
||||
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
|
||||
fprintf(stderr, "v%lu:", static_cast<unsigned long>(i));
|
||||
VirtualRegister &vreg = vregs[i];
|
||||
for (size_t j = 0; j < vreg.numIntervals(); j++) {
|
||||
@ -1288,8 +1307,10 @@ BacktrackingAllocator::dumpAllocations()
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
for (size_t i = 0; i < AnyRegister::Total; i++) {
|
||||
fprintf(stderr, "reg %s:\n", AnyRegister::FromCode(i).name());
|
||||
registers[i].allocations.forEach(PrintLiveIntervalRange());
|
||||
if (registers[i].allocatable) {
|
||||
fprintf(stderr, "reg %s:\n", AnyRegister::FromCode(i).name());
|
||||
registers[i].allocations.forEach(PrintLiveIntervalRange());
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
@ -1342,7 +1363,7 @@ BacktrackingAllocator::minimalDef(const LiveInterval *interval, LInstruction *in
|
||||
{
|
||||
// Whether interval is a minimal interval capturing a definition at ins.
|
||||
return (interval->end() <= minimalDefEnd(ins).next()) &&
|
||||
(interval->start() == inputOf(ins) || interval->start() == outputOf(ins));
|
||||
((!ins->isPhi() && interval->start() == inputOf(ins)) || interval->start() == outputOf(ins));
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1530,10 +1551,10 @@ BacktrackingAllocator::trySplitAcrossHotcode(LiveInterval *interval, bool *succe
|
||||
if (postInterval && !newIntervals.append(postInterval))
|
||||
return false;
|
||||
|
||||
distributeUses(interval, newIntervals);
|
||||
|
||||
*success = true;
|
||||
return distributeUses(interval, newIntervals) &&
|
||||
split(interval, newIntervals) &&
|
||||
requeueIntervals(newIntervals);
|
||||
return split(interval, newIntervals) && requeueIntervals(newIntervals);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1555,22 +1576,9 @@ BacktrackingAllocator::trySplitAfterLastRegisterUse(LiveInterval *interval, bool
|
||||
JS_ASSERT(iter->pos >= lastUse);
|
||||
lastUse = inputOf(ins);
|
||||
|
||||
switch (use->policy()) {
|
||||
case LUse::ANY:
|
||||
if (isReusedInput(iter->use, ins, /* considerCopy = */ true)) {
|
||||
lastRegisterFrom = inputOf(ins);
|
||||
lastRegisterTo = iter->pos.next();
|
||||
}
|
||||
break;
|
||||
|
||||
case LUse::REGISTER:
|
||||
case LUse::FIXED:
|
||||
if (isRegisterUse(use, ins, /* considerCopy = */ true)) {
|
||||
lastRegisterFrom = inputOf(ins);
|
||||
lastRegisterTo = iter->pos.next();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1602,10 +1610,10 @@ BacktrackingAllocator::trySplitAfterLastRegisterUse(LiveInterval *interval, bool
|
||||
if (!newIntervals.append(preInterval) || !newIntervals.append(postInterval))
|
||||
return false;
|
||||
|
||||
distributeUses(interval, newIntervals);
|
||||
|
||||
*success = true;
|
||||
return distributeUses(interval, newIntervals) &&
|
||||
split(interval, newIntervals) &&
|
||||
requeueIntervals(newIntervals);
|
||||
return split(interval, newIntervals) && requeueIntervals(newIntervals);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -192,13 +192,13 @@ class BacktrackingAllocator : public LiveRangeAllocator<BacktrackingVirtualRegis
|
||||
bool tryAllocateGroupRegister(PhysicalRegister &r, VirtualRegisterGroup *group,
|
||||
bool *psuccess, bool *pfixed, LiveInterval **pconflicting);
|
||||
bool evictInterval(LiveInterval *interval);
|
||||
bool distributeUses(LiveInterval *interval, const LiveIntervalVector &newIntervals);
|
||||
void distributeUses(LiveInterval *interval, const LiveIntervalVector &newIntervals);
|
||||
bool split(LiveInterval *interval, const LiveIntervalVector &newIntervals);
|
||||
bool requeueIntervals(const LiveIntervalVector &newIntervals);
|
||||
void spill(LiveInterval *interval);
|
||||
|
||||
bool isReusedInput(LUse *use, LInstruction *ins, bool considerCopy = false);
|
||||
bool isRegisterUse(LUse *use, LInstruction *ins);
|
||||
bool isReusedInput(LUse *use, LInstruction *ins, bool considerCopy);
|
||||
bool isRegisterUse(LUse *use, LInstruction *ins, bool considerCopy = false);
|
||||
bool isRegisterDefinition(LiveInterval *interval);
|
||||
bool addLiveInterval(LiveIntervalVector &intervals, uint32_t vreg,
|
||||
LiveInterval *spillInterval,
|
||||
|
@ -596,6 +596,14 @@ IonBuilder::build()
|
||||
if (instrumentedProfiling())
|
||||
current->add(MFunctionBoundary::New(script(), MFunctionBoundary::Enter));
|
||||
|
||||
// Guard against over-recursion. Do this before we start unboxing, since
|
||||
// this will create an OSI point that will read the incoming argument
|
||||
// values, which is nice to do before their last real use, to minimize
|
||||
// register/stack pressure.
|
||||
MCheckOverRecursed *check = new MCheckOverRecursed;
|
||||
current->add(check);
|
||||
check->setResumePoint(current->entryResumePoint());
|
||||
|
||||
// Parameters have been checked to correspond to the typeset, now we unbox
|
||||
// what we can in an infallible manner.
|
||||
rewriteParameters();
|
||||
@ -607,11 +615,6 @@ IonBuilder::build()
|
||||
if (info().needsArgsObj() && !initArgumentsObject())
|
||||
return false;
|
||||
|
||||
// Guard against over-recursion.
|
||||
MCheckOverRecursed *check = new MCheckOverRecursed;
|
||||
current->add(check);
|
||||
check->setResumePoint(current->entryResumePoint());
|
||||
|
||||
// Prevent |this| from being DCE'd: necessary for constructors.
|
||||
if (info().fun())
|
||||
current->getSlot(info().thisSlot())->setGuard();
|
||||
@ -6529,9 +6532,9 @@ IonBuilder::getElemTryScalarElemOfTypedObject(bool *emitted,
|
||||
JS_ASSERT(objTypeReprs.allOfArrayKind());
|
||||
|
||||
// Must always be loading the same scalar type
|
||||
if (elemTypeReprs.length() != 1)
|
||||
if (!elemTypeReprs.singleton())
|
||||
return true;
|
||||
ScalarTypeRepresentation *elemTypeRepr = elemTypeReprs.get(0)->asScalar();
|
||||
ScalarTypeRepresentation *elemTypeRepr = elemTypeReprs.getTypeRepresentation()->asScalar();
|
||||
|
||||
// Get the length.
|
||||
size_t lenOfAll = objTypeReprs.arrayLength();
|
||||
@ -6550,40 +6553,19 @@ IonBuilder::getElemTryScalarElemOfTypedObject(bool *emitted,
|
||||
// Typed-object accesses usually in bounds (bail out otherwise).
|
||||
index = addBoundsCheck(index, length);
|
||||
|
||||
// Since we passed the bounds check, it is impossible for the
|
||||
// result of multiplication to overflow; so enable imul path.
|
||||
const int32_t alignment = elemTypeRepr->alignment();
|
||||
MMul *indexAsByteOffset = MMul::New(index, constantInt(alignment),
|
||||
MIRType_Int32, MMul::Integer);
|
||||
current->add(indexAsByteOffset);
|
||||
|
||||
// Find location within the owner object.
|
||||
MDefinition *owner;
|
||||
MDefinition *indexFromOwner;
|
||||
if (obj->isNewDerivedTypedObject()) {
|
||||
MNewDerivedTypedObject *ins = obj->toNewDerivedTypedObject();
|
||||
MDefinition *ownerOffset = ins->offset();
|
||||
|
||||
// Typed array offsets are expressed in units of the (array)
|
||||
// element alignment. The binary data uses byte units for
|
||||
// offsets (such as the owner offset here).
|
||||
|
||||
MConstant *alignment = MConstant::New(Int32Value(elemTypeRepr->alignment()));
|
||||
current->add(alignment);
|
||||
|
||||
MDiv *scaledOffset = MDiv::NewAsmJS(ownerOffset, alignment, MIRType_Int32);
|
||||
current->add(scaledOffset);
|
||||
|
||||
MAdd *scaledOffsetPlusIndex = MAdd::NewAsmJS(scaledOffset, index,
|
||||
MIRType_Int32);
|
||||
current->add(scaledOffsetPlusIndex);
|
||||
|
||||
owner = ins->owner();
|
||||
indexFromOwner = scaledOffsetPlusIndex;
|
||||
} else {
|
||||
owner = obj;
|
||||
indexFromOwner = index;
|
||||
}
|
||||
|
||||
// Load the element data.
|
||||
MTypedObjectElements *elements = MTypedObjectElements::New(owner);
|
||||
current->add(elements);
|
||||
MDefinition *elements, *scaledOffset;
|
||||
loadTypedObjectElements(obj, indexAsByteOffset, alignment, &elements, &scaledOffset);
|
||||
|
||||
// Load the element.
|
||||
MLoadTypedArrayElement *load = MLoadTypedArrayElement::New(elements, indexFromOwner, elemTypeRepr->type());
|
||||
MLoadTypedArrayElement *load = MLoadTypedArrayElement::New(elements, scaledOffset, elemTypeRepr->type());
|
||||
current->add(load);
|
||||
current->push(load);
|
||||
|
||||
@ -6613,8 +6595,7 @@ IonBuilder::getElemTryComplexElemOfTypedObject(bool *emitted,
|
||||
JS_ASSERT(objTypeReprs.allOfArrayKind());
|
||||
|
||||
MDefinition *type = loadTypedObjectType(obj);
|
||||
MInstruction *elemType = MLoadFixedSlot::New(type, JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE);
|
||||
current->add(elemType);
|
||||
MDefinition *elemType = typeObjectForElementFromArrayStructType(type);
|
||||
|
||||
// Get the length.
|
||||
size_t lenOfAll = objTypeReprs.arrayLength();
|
||||
@ -6644,33 +6625,14 @@ IonBuilder::getElemTryComplexElemOfTypedObject(bool *emitted,
|
||||
current->add(indexAsByteOffset);
|
||||
|
||||
// Find location within the owner object.
|
||||
MDefinition *owner;
|
||||
MDefinition *indexAsByteOffsetFromOwner;
|
||||
if (obj->isNewDerivedTypedObject()) {
|
||||
MNewDerivedTypedObject *ins = obj->toNewDerivedTypedObject();
|
||||
MDefinition *ownerOffset = ins->offset();
|
||||
|
||||
MAdd *offsetPlusScaledIndex = MAdd::NewAsmJS(ownerOffset,
|
||||
indexAsByteOffset,
|
||||
MIRType_Int32);
|
||||
current->add(offsetPlusScaledIndex);
|
||||
|
||||
owner = ins->owner();
|
||||
indexAsByteOffsetFromOwner = offsetPlusScaledIndex;
|
||||
} else {
|
||||
owner = obj;
|
||||
indexAsByteOffsetFromOwner = indexAsByteOffset;
|
||||
}
|
||||
|
||||
// Load the element data.
|
||||
MTypedObjectElements *elements = MTypedObjectElements::New(owner);
|
||||
current->add(elements);
|
||||
MDefinition *owner, *ownerOffset;
|
||||
loadTypedObjectData(obj, indexAsByteOffset, &owner, &ownerOffset);
|
||||
|
||||
// Create the derived type object.
|
||||
MInstruction *derived = new MNewDerivedTypedObject(elemTypeReprs,
|
||||
elemType,
|
||||
owner,
|
||||
indexAsByteOffsetFromOwner);
|
||||
ownerOffset);
|
||||
|
||||
types::TemporaryTypeSet *resultTypes = bytecodeTypes(pc);
|
||||
derived->setResultTypeSet(resultTypes);
|
||||
@ -8228,22 +8190,19 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted,
|
||||
types::TemporaryTypeSet *resultTypes)
|
||||
{
|
||||
// Must always be loading the same scalar type
|
||||
if (fieldTypeReprs.length() != 1)
|
||||
if (!fieldTypeReprs.singleton())
|
||||
return true;
|
||||
ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.get(0)->asScalar();
|
||||
ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.getTypeRepresentation()->asScalar();
|
||||
|
||||
// OK!
|
||||
*emitted = true;
|
||||
// OK, perform the optimization
|
||||
|
||||
MDefinition *typedObj = current->pop();
|
||||
|
||||
// Find location within the owner object.
|
||||
MDefinition *owner, *ownerOffset;
|
||||
loadTypedObjectData(typedObj, fieldOffset, &owner, &ownerOffset);
|
||||
|
||||
// Load the element data.
|
||||
MTypedObjectElements *elements = MTypedObjectElements::New(owner);
|
||||
current->add(elements);
|
||||
MDefinition *elements, *scaledOffset;
|
||||
loadTypedObjectElements(typedObj, constantInt(fieldOffset),
|
||||
fieldTypeRepr->alignment(),
|
||||
&elements, &scaledOffset);
|
||||
|
||||
// Reading from an Uint32Array will result in a double for values
|
||||
// that don't fit in an int32. We have to bailout if this happens
|
||||
@ -8251,14 +8210,6 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted,
|
||||
bool allowDouble = resultTypes->hasType(types::Type::DoubleType());
|
||||
MIRType knownType = MIRTypeForTypedArrayRead(fieldTypeRepr->type(), allowDouble);
|
||||
|
||||
// Typed array offsets are expressed in units of the alignment,
|
||||
// and the binary data API guarantees all offsets are properly
|
||||
// aligned. So just do the divide.
|
||||
MConstant *alignment = MConstant::New(Int32Value(fieldTypeRepr->alignment()));
|
||||
current->add(alignment);
|
||||
MDiv *scaledOffset = MDiv::NewAsmJS(ownerOffset, alignment, MIRType_Int32);
|
||||
current->add(scaledOffset);
|
||||
|
||||
MLoadTypedArrayElement *load =
|
||||
MLoadTypedArrayElement::New(elements, scaledOffset,
|
||||
fieldTypeRepr->type());
|
||||
@ -8266,6 +8217,7 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted,
|
||||
load->setResultTypeSet(resultTypes);
|
||||
current->add(load);
|
||||
current->push(load);
|
||||
*emitted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -8281,7 +8233,8 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
|
||||
if (fieldIndex == SIZE_MAX)
|
||||
return true;
|
||||
|
||||
*emitted = true;
|
||||
// OK, perform the optimization
|
||||
|
||||
MDefinition *typedObj = current->pop();
|
||||
|
||||
// Identify the type object for the field.
|
||||
@ -8290,7 +8243,8 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
|
||||
|
||||
// Find location within the owner object.
|
||||
MDefinition *owner, *ownerOffset;
|
||||
loadTypedObjectData(typedObj, fieldOffset, &owner, &ownerOffset);
|
||||
loadTypedObjectData(typedObj, constantInt(fieldOffset),
|
||||
&owner, &ownerOffset);
|
||||
|
||||
// Create the derived type object.
|
||||
MInstruction *derived = new MNewDerivedTypedObject(fieldTypeReprs,
|
||||
@ -8300,6 +8254,7 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
|
||||
derived->setResultTypeSet(resultTypes);
|
||||
current->add(derived);
|
||||
current->push(derived);
|
||||
*emitted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -8749,43 +8704,34 @@ IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj,
|
||||
return true;
|
||||
|
||||
case TypeRepresentation::Scalar:
|
||||
break;
|
||||
return setPropTryScalarPropOfTypedObject(emitted, obj, fieldOffset,
|
||||
value, fieldTypeReprs);
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("Unknown kind");
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::setPropTryScalarPropOfTypedObject(bool *emitted,
|
||||
MDefinition *obj,
|
||||
int32_t fieldOffset,
|
||||
MDefinition *value,
|
||||
TypeRepresentationSet fieldTypeReprs)
|
||||
{
|
||||
// Must always be storing the same scalar type
|
||||
if (fieldTypeReprs.length() != 1)
|
||||
if (!fieldTypeReprs.singleton())
|
||||
return true;
|
||||
ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.get(0)->asScalar();
|
||||
ScalarTypeRepresentation *fieldTypeRepr =
|
||||
fieldTypeReprs.getTypeRepresentation()->asScalar();
|
||||
|
||||
// OK!
|
||||
*emitted = true;
|
||||
// OK! Perform the optimization.
|
||||
|
||||
MTypedObjectElements *elements = MTypedObjectElements::New(obj);
|
||||
current->add(elements);
|
||||
|
||||
// Typed array offsets are expressed in units of the alignment,
|
||||
// and the binary data API guarantees all offsets are properly
|
||||
// aligned.
|
||||
JS_ASSERT(fieldOffset % fieldTypeRepr->alignment() == 0);
|
||||
int32_t scaledFieldOffset = fieldOffset / fieldTypeRepr->alignment();
|
||||
|
||||
MConstant *offset = MConstant::New(Int32Value(scaledFieldOffset));
|
||||
current->add(offset);
|
||||
|
||||
// Clamp value to [0, 255] for Uint8ClampedArray.
|
||||
MDefinition *toWrite = value;
|
||||
if (fieldTypeRepr->type() == ScalarTypeRepresentation::TYPE_UINT8_CLAMPED) {
|
||||
toWrite = MClampToUint8::New(value);
|
||||
current->add(toWrite->toInstruction());
|
||||
}
|
||||
|
||||
MStoreTypedArrayElement *store =
|
||||
MStoreTypedArrayElement::New(elements, offset, toWrite,
|
||||
fieldTypeRepr->type());
|
||||
current->add(store);
|
||||
if (!storeScalarTypedObjectValue(obj, constantInt(fieldOffset), fieldTypeRepr, value))
|
||||
return false;
|
||||
|
||||
current->push(value);
|
||||
|
||||
*emitted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -9620,12 +9566,12 @@ IonBuilder::loadTypedObjectType(MDefinition *typedObj)
|
||||
// into dead code).
|
||||
void
|
||||
IonBuilder::loadTypedObjectData(MDefinition *typedObj,
|
||||
int32_t offset,
|
||||
MDefinition *offset,
|
||||
MDefinition **owner,
|
||||
MDefinition **ownerOffset)
|
||||
{
|
||||
MConstant *offsetDef = MConstant::New(Int32Value(offset));
|
||||
current->add(offsetDef);
|
||||
JS_ASSERT(typedObj->type() == MIRType_Object);
|
||||
JS_ASSERT(offset->type() == MIRType_Int32);
|
||||
|
||||
// Shortcircuit derived type objects, meaning the intermediate
|
||||
// objects created to represent `a.b` in an expression like
|
||||
@ -9636,8 +9582,7 @@ IonBuilder::loadTypedObjectData(MDefinition *typedObj,
|
||||
// If we see that the
|
||||
MNewDerivedTypedObject *ins = typedObj->toNewDerivedTypedObject();
|
||||
|
||||
MAdd *offsetAdd = MAdd::NewAsmJS(ins->offset(), offsetDef,
|
||||
MIRType_Int32);
|
||||
MAdd *offsetAdd = MAdd::NewAsmJS(ins->offset(), offset, MIRType_Int32);
|
||||
current->add(offsetAdd);
|
||||
|
||||
*owner = ins->owner();
|
||||
@ -9646,7 +9591,38 @@ IonBuilder::loadTypedObjectData(MDefinition *typedObj,
|
||||
}
|
||||
|
||||
*owner = typedObj;
|
||||
*ownerOffset = offsetDef;
|
||||
*ownerOffset = offset;
|
||||
}
|
||||
|
||||
// Takes as input a typed object, an offset into that typed object's
|
||||
// memory, and the type repr of the data found at that offset. Returns
|
||||
// the elements pointer and a scaled offset. The scaled offset is
|
||||
// expressed in units of `unit`; when working with typed array MIR,
|
||||
// this is typically the alignment.
|
||||
void
|
||||
IonBuilder::loadTypedObjectElements(MDefinition *typedObj,
|
||||
MDefinition *offset,
|
||||
int32_t unit,
|
||||
MDefinition **ownerElements,
|
||||
MDefinition **ownerScaledOffset)
|
||||
{
|
||||
MDefinition *owner, *ownerOffset;
|
||||
loadTypedObjectData(typedObj, offset, &owner, &ownerOffset);
|
||||
|
||||
// Load the element data.
|
||||
MTypedObjectElements *elements = MTypedObjectElements::New(owner);
|
||||
current->add(elements);
|
||||
|
||||
// Scale to a different unit for compat with typed array MIRs.
|
||||
if (unit != 1) {
|
||||
MDiv *scaledOffset = MDiv::NewAsmJS(ownerOffset, constantInt(unit), MIRType_Int32);
|
||||
current->add(scaledOffset);
|
||||
*ownerScaledOffset = scaledOffset;
|
||||
} else {
|
||||
*ownerScaledOffset = ownerOffset;
|
||||
}
|
||||
|
||||
*ownerElements = elements;
|
||||
}
|
||||
|
||||
// Looks up the offset/type-repr-set of the field `id`, given the type
|
||||
@ -9674,7 +9650,7 @@ IonBuilder::lookupTypedObjectField(MDefinition *typedObj,
|
||||
fieldTypeReprs, fieldIndex))
|
||||
return false;
|
||||
if (fieldTypeReprs->empty())
|
||||
return false;
|
||||
return true;
|
||||
|
||||
// Field offset must be representable as signed integer.
|
||||
if (offset >= size_t(INT_MAX)) {
|
||||
@ -9688,6 +9664,18 @@ IonBuilder::lookupTypedObjectField(MDefinition *typedObj,
|
||||
return true;
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
IonBuilder::typeObjectForElementFromArrayStructType(MDefinition *typeObj)
|
||||
{
|
||||
MInstruction *elemType = MLoadFixedSlot::New(typeObj, JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE);
|
||||
current->add(elemType);
|
||||
|
||||
MInstruction *unboxElemType = MUnbox::New(elemType, MIRType_Object, MUnbox::Infallible);
|
||||
current->add(unboxElemType);
|
||||
|
||||
return unboxElemType;
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
|
||||
size_t fieldIndex)
|
||||
@ -9697,16 +9685,60 @@ IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
|
||||
MInstruction *fieldTypes = MLoadFixedSlot::New(typeObj, JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES);
|
||||
current->add(fieldTypes);
|
||||
|
||||
MInstruction *unboxFieldTypes = MUnbox::New(fieldTypes, MIRType_Object, MUnbox::Infallible);
|
||||
current->add(unboxFieldTypes);
|
||||
|
||||
// Index into list with index of field.
|
||||
|
||||
MInstruction *fieldTypesElements = MElements::New(fieldTypes);
|
||||
MInstruction *fieldTypesElements = MElements::New(unboxFieldTypes);
|
||||
current->add(fieldTypesElements);
|
||||
|
||||
MConstant *fieldIndexDef = MConstant::New(Int32Value(fieldIndex));
|
||||
current->add(fieldIndexDef);
|
||||
MConstant *fieldIndexDef = constantInt(fieldIndex);
|
||||
|
||||
MInstruction *fieldType = MLoadElement::New(fieldTypesElements, fieldIndexDef, false, false);
|
||||
current->add(fieldType);
|
||||
|
||||
return fieldType;
|
||||
MInstruction *unboxFieldType = MUnbox::New(fieldType, MIRType_Object, MUnbox::Infallible);
|
||||
current->add(unboxFieldType);
|
||||
|
||||
return unboxFieldType;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::storeScalarTypedObjectValue(MDefinition *typedObj,
|
||||
MDefinition *offset,
|
||||
ScalarTypeRepresentation *typeRepr,
|
||||
MDefinition *value)
|
||||
{
|
||||
// Find location within the owner object.
|
||||
MDefinition *elements, *scaledOffset;
|
||||
loadTypedObjectElements(typedObj, offset, typeRepr->alignment(), &elements, &scaledOffset);
|
||||
|
||||
// Clamp value to [0, 255] when type is Uint8Clamped
|
||||
MDefinition *toWrite = value;
|
||||
if (typeRepr->type() == ScalarTypeRepresentation::TYPE_UINT8_CLAMPED) {
|
||||
toWrite = MClampToUint8::New(value);
|
||||
current->add(toWrite->toInstruction());
|
||||
}
|
||||
|
||||
MStoreTypedArrayElement *store =
|
||||
MStoreTypedArrayElement::New(elements, scaledOffset, toWrite,
|
||||
typeRepr->type());
|
||||
current->add(store);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MConstant *
|
||||
IonBuilder::constant(const Value &v)
|
||||
{
|
||||
MConstant *c = MConstant::New(v);
|
||||
current->add(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
MConstant *
|
||||
IonBuilder::constantInt(int32_t i)
|
||||
{
|
||||
return constant(Int32Value(i));
|
||||
}
|
||||
|
@ -327,6 +327,9 @@ class IonBuilder : public MIRGenerator
|
||||
bool initArgumentsObject();
|
||||
bool pushConstant(const Value &v);
|
||||
|
||||
MConstant *constant(const Value &v);
|
||||
MConstant *constantInt(int32_t i);
|
||||
|
||||
// Add a guard which ensure that the set of type which goes through this
|
||||
// generated code correspond to the observed types for the bytecode.
|
||||
bool pushTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, bool needBarrier);
|
||||
@ -400,6 +403,11 @@ class IonBuilder : public MIRGenerator
|
||||
types::TemporaryTypeSet *objTypes);
|
||||
bool setPropTryTypedObject(bool *emitted, MDefinition *obj,
|
||||
PropertyName *name, MDefinition *value);
|
||||
bool setPropTryScalarPropOfTypedObject(bool *emitted,
|
||||
MDefinition *obj,
|
||||
int32_t fieldOffset,
|
||||
MDefinition *value,
|
||||
TypeRepresentationSet fieldTypeReprs);
|
||||
bool setPropTryCache(bool *emitted, MDefinition *obj,
|
||||
PropertyName *name, MDefinition *value,
|
||||
bool barrier, types::TemporaryTypeSet *objTypes);
|
||||
@ -413,12 +421,22 @@ class IonBuilder : public MIRGenerator
|
||||
TypeRepresentationSet *fieldTypeReprs,
|
||||
size_t *fieldIndex);
|
||||
MDefinition *loadTypedObjectType(MDefinition *value);
|
||||
void loadTypedObjectData(MDefinition *inOwner,
|
||||
int32_t inOffset,
|
||||
MDefinition **outOwner,
|
||||
MDefinition **outOffset);
|
||||
void loadTypedObjectData(MDefinition *typedObj,
|
||||
MDefinition *offset,
|
||||
MDefinition **owner,
|
||||
MDefinition **ownerOffset);
|
||||
void loadTypedObjectElements(MDefinition *typedObj,
|
||||
MDefinition *offset,
|
||||
int32_t unit,
|
||||
MDefinition **ownerElements,
|
||||
MDefinition **ownerScaledOffset);
|
||||
MDefinition *typeObjectForElementFromArrayStructType(MDefinition *typedObj);
|
||||
MDefinition *typeObjectForFieldFromStructType(MDefinition *type,
|
||||
size_t fieldIndex);
|
||||
bool storeScalarTypedObjectValue(MDefinition *typedObj,
|
||||
MDefinition *offset,
|
||||
ScalarTypeRepresentation *typeRepr,
|
||||
MDefinition *value);
|
||||
|
||||
// jsop_setelem() helpers.
|
||||
bool setElemTryTyped(bool *emitted, MDefinition *object,
|
||||
|
@ -3156,12 +3156,27 @@ GetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, c
|
||||
GetElementIC::canAttachTypedArrayElement(JSObject *obj, const Value &idval,
|
||||
TypedOrValueRegister output)
|
||||
{
|
||||
if (!obj->is<TypedArrayObject>() ||
|
||||
(!(idval.isInt32()) &&
|
||||
!(idval.isString() && GetIndexFromString(idval.toString()) != UINT32_MAX)))
|
||||
{
|
||||
if (!obj->is<TypedArrayObject>())
|
||||
return false;
|
||||
|
||||
if (!idval.isInt32() && !idval.isString())
|
||||
return false;
|
||||
|
||||
|
||||
// Don't emit a stub if the access is out of bounds. We make to make
|
||||
// certain that we monitor the type coming out of the typed array when
|
||||
// we generate the stub. Out of bounds accesses will hit the fallback
|
||||
// path.
|
||||
uint32_t index;
|
||||
if (idval.isInt32()) {
|
||||
index = idval.toInt32();
|
||||
} else {
|
||||
index = GetIndexFromString(idval.toString());
|
||||
if (index == UINT32_MAX)
|
||||
return false;
|
||||
}
|
||||
if (index >= obj->as<TypedArrayObject>().length())
|
||||
return false;
|
||||
|
||||
// The output register is not yet specialized as a float register, the only
|
||||
// way to accept float typed arrays for now is to return a Value type.
|
||||
|
@ -549,30 +549,41 @@ HandleException(ResumeFromException *rfe)
|
||||
// Search each inlined frame for live iterator objects, and close
|
||||
// them.
|
||||
InlineFrameIterator frames(cx, &iter);
|
||||
|
||||
// Invalidation state will be the same for all inlined scripts in the frame.
|
||||
IonScript *ionScript = nullptr;
|
||||
bool invalidated = iter.checkInvalidation(&ionScript);
|
||||
|
||||
for (;;) {
|
||||
HandleExceptionIon(cx, frames, rfe, &overrecursed);
|
||||
|
||||
if (rfe->kind == ResumeFromException::RESUME_BAILOUT) {
|
||||
IonScript *ionScript = nullptr;
|
||||
if (iter.checkInvalidation(&ionScript))
|
||||
if (invalidated)
|
||||
ionScript->decref(cx->runtime()->defaultFreeOp());
|
||||
return;
|
||||
}
|
||||
|
||||
JS_ASSERT(rfe->kind == ResumeFromException::RESUME_ENTRY_FRAME);
|
||||
|
||||
// Figure out whether SPS frame was pushed for this frame or not.
|
||||
// Even if profiler is enabled, the frame being popped might have
|
||||
// been entered prior to SPS being enabled, and thus not have
|
||||
// a pushed SPS frame.
|
||||
bool popSPSFrame = cx->runtime()->spsProfiler.enabled();
|
||||
if (invalidated)
|
||||
popSPSFrame = ionScript->hasSPSInstrumentation();
|
||||
|
||||
// When profiling, each frame popped needs a notification that
|
||||
// the function has exited, so invoke the probe that a function
|
||||
// is exiting.
|
||||
JSScript *script = frames.script();
|
||||
probes::ExitScript(cx, script, script->function(), nullptr);
|
||||
probes::ExitScript(cx, script, script->function(), popSPSFrame);
|
||||
if (!frames.more())
|
||||
break;
|
||||
++frames;
|
||||
}
|
||||
|
||||
IonScript *ionScript = nullptr;
|
||||
if (iter.checkInvalidation(&ionScript))
|
||||
if (invalidated)
|
||||
ionScript->decref(cx->runtime()->defaultFreeOp());
|
||||
|
||||
} else if (iter.isBaselineJS()) {
|
||||
@ -585,7 +596,8 @@ HandleException(ResumeFromException *rfe)
|
||||
|
||||
// Unwind profiler pseudo-stack
|
||||
JSScript *script = iter.script();
|
||||
probes::ExitScript(cx, script, script->function(), iter.baselineFrame());
|
||||
probes::ExitScript(cx, script, script->function(),
|
||||
iter.baselineFrame()->hasPushedSPSFrame());
|
||||
// After this point, any pushed SPS frame would have been popped if it needed
|
||||
// to be. Unset the flag here so that if we call DebugEpilogue below,
|
||||
// it doesn't try to pop the SPS frame again.
|
||||
|
@ -236,8 +236,17 @@ PrintUse(char *buf, size_t size, const LUse *use)
|
||||
JS_snprintf(buf, size, "v%d:%s", use->virtualRegister(),
|
||||
Registers::GetName(Registers::Code(use->registerCode())));
|
||||
break;
|
||||
default:
|
||||
case LUse::ANY:
|
||||
JS_snprintf(buf, size, "v%d:r?", use->virtualRegister());
|
||||
break;
|
||||
case LUse::KEEPALIVE:
|
||||
JS_snprintf(buf, size, "v%d:*", use->virtualRegister());
|
||||
break;
|
||||
case LUse::RECOVERED_INPUT:
|
||||
JS_snprintf(buf, size, "v%d:**", use->virtualRegister());
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("invalid use policy");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,9 +36,7 @@ Requirement::priority() const
|
||||
bool
|
||||
LiveInterval::Range::contains(const Range *other) const
|
||||
{
|
||||
Range pre, inside, post;
|
||||
intersect(other, &pre, &inside, &post);
|
||||
return inside.from == other->from && inside.to == other->to;
|
||||
return from <= other->from && to >= other->to;
|
||||
}
|
||||
|
||||
void
|
||||
@ -420,7 +418,7 @@ LiveRangeAllocator<VREG>::init()
|
||||
|
||||
// Build virtual register objects
|
||||
for (size_t i = 0; i < graph.numBlocks(); i++) {
|
||||
if (mir->shouldCancel("LSRA create data structures (main loop)"))
|
||||
if (mir->shouldCancel("Create data structures (main loop)"))
|
||||
return false;
|
||||
|
||||
LBlock *block = graph.getBlock(i);
|
||||
@ -498,7 +496,7 @@ LiveRangeAllocator<VREG>::buildLivenessInfo()
|
||||
return false;
|
||||
|
||||
for (size_t i = graph.numBlocks(); i > 0; i--) {
|
||||
if (mir->shouldCancel("LSRA Build Liveness Info (main loop)"))
|
||||
if (mir->shouldCancel("Build Liveness Info (main loop)"))
|
||||
return false;
|
||||
|
||||
LBlock *block = graph.getBlock(i - 1);
|
||||
|
@ -51,7 +51,9 @@ class Requirement
|
||||
Requirement(LAllocation fixed)
|
||||
: kind_(FIXED),
|
||||
allocation_(fixed)
|
||||
{ }
|
||||
{
|
||||
JS_ASSERT(fixed == LAllocation() || !fixed.isUse());
|
||||
}
|
||||
|
||||
// Only useful as a hint, encodes where the fixed requirement is used to
|
||||
// avoid allocating a fixed register too early.
|
||||
@ -59,7 +61,9 @@ class Requirement
|
||||
: kind_(FIXED),
|
||||
allocation_(fixed),
|
||||
position_(at)
|
||||
{ }
|
||||
{
|
||||
JS_ASSERT(fixed == LAllocation() || !fixed.isUse());
|
||||
}
|
||||
|
||||
Requirement(uint32_t vreg, CodePosition at)
|
||||
: kind_(SAME_AS_OTHER),
|
||||
@ -78,6 +82,7 @@ class Requirement
|
||||
|
||||
uint32_t virtualRegister() const {
|
||||
JS_ASSERT(allocation_.isUse());
|
||||
JS_ASSERT(kind() == SAME_AS_OTHER);
|
||||
return allocation_.toUse()->virtualRegister();
|
||||
}
|
||||
|
||||
@ -618,6 +623,17 @@ class LiveRangeAllocator : public RegisterAllocator
|
||||
return addMove(moves, from, to);
|
||||
}
|
||||
|
||||
size_t findFirstNonCallSafepoint(CodePosition from) const
|
||||
{
|
||||
size_t i = 0;
|
||||
for (; i < graph.numNonCallSafepoints(); i++) {
|
||||
const LInstruction *ins = graph.getNonCallSafepoint(i);
|
||||
if (from <= (forLSRA ? inputOf(ins) : outputOf(ins)))
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void addLiveRegistersForInterval(VirtualRegister *reg, LiveInterval *interval)
|
||||
{
|
||||
// Fill in the live register sets for all non-call safepoints.
|
||||
@ -633,7 +649,7 @@ class LiveRangeAllocator : public RegisterAllocator
|
||||
size_t i = findFirstNonCallSafepoint(start);
|
||||
for (; i < graph.numNonCallSafepoints(); i++) {
|
||||
LInstruction *ins = graph.getNonCallSafepoint(i);
|
||||
CodePosition pos = inputOf(ins);
|
||||
CodePosition pos = forLSRA ? inputOf(ins) : outputOf(ins);
|
||||
|
||||
// Safepoints are sorted, so we can shortcut out of this loop
|
||||
// if we go out of range.
|
||||
|
@ -3673,8 +3673,15 @@ class MPowHalf
|
||||
: public MUnaryInstruction,
|
||||
public DoublePolicy<0>
|
||||
{
|
||||
bool operandIsNeverNegativeInfinity_;
|
||||
bool operandIsNeverNegativeZero_;
|
||||
bool operandIsNeverNaN_;
|
||||
|
||||
MPowHalf(MDefinition *input)
|
||||
: MUnaryInstruction(input)
|
||||
: MUnaryInstruction(input),
|
||||
operandIsNeverNegativeInfinity_(false),
|
||||
operandIsNeverNegativeZero_(false),
|
||||
operandIsNeverNaN_(false)
|
||||
{
|
||||
setResultType(MIRType_Double);
|
||||
setMovable();
|
||||
@ -3688,12 +3695,22 @@ class MPowHalf
|
||||
bool congruentTo(MDefinition *ins) const {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
bool operandIsNeverNegativeInfinity() const {
|
||||
return operandIsNeverNegativeInfinity_;
|
||||
}
|
||||
bool operandIsNeverNegativeZero() const {
|
||||
return operandIsNeverNegativeZero_;
|
||||
}
|
||||
bool operandIsNeverNaN() const {
|
||||
return operandIsNeverNaN_;
|
||||
}
|
||||
TypePolicy *typePolicy() {
|
||||
return this;
|
||||
}
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
void collectRangeInfo();
|
||||
};
|
||||
|
||||
// Inline implementation of Math.random().
|
||||
|
@ -25,6 +25,7 @@ using mozilla::Abs;
|
||||
using mozilla::CountLeadingZeroes32;
|
||||
using mozilla::DoubleEqualsInt32;
|
||||
using mozilla::ExponentComponent;
|
||||
using mozilla::FloorLog2;
|
||||
using mozilla::IsInfinite;
|
||||
using mozilla::IsFinite;
|
||||
using mozilla::IsNaN;
|
||||
@ -284,6 +285,25 @@ SymbolicBound::print(Sprinter &sp) const
|
||||
sum.print(sp);
|
||||
}
|
||||
|
||||
// Test whether the given range's exponent tells us anything that its lower
|
||||
// and upper bound values don't.
|
||||
static bool
|
||||
IsExponentInteresting(const Range *r)
|
||||
{
|
||||
// If it lacks either a lower or upper bound, the exponent is interesting.
|
||||
if (!r->hasInt32Bounds())
|
||||
return true;
|
||||
|
||||
// Otherwise if there's no fractional part, the lower and upper bounds,
|
||||
// which are integers, are perfectly precise.
|
||||
if (!r->canHaveFractionalPart())
|
||||
return false;
|
||||
|
||||
// Otherwise, if the bounds are conservatively rounded across a power-of-two
|
||||
// boundary, the exponent may imply a tighter range.
|
||||
return FloorLog2(Max(Abs(r->lower()), Abs(r->upper()))) > r->exponent();
|
||||
}
|
||||
|
||||
void
|
||||
Range::print(Sprinter &sp) const
|
||||
{
|
||||
@ -320,12 +340,14 @@ Range::print(Sprinter &sp) const
|
||||
}
|
||||
|
||||
sp.printf("]");
|
||||
if (max_exponent_ == IncludesInfinityAndNaN)
|
||||
sp.printf(" (U inf U NaN)", max_exponent_);
|
||||
else if (max_exponent_ == IncludesInfinity)
|
||||
sp.printf(" (U inf)");
|
||||
else if (!hasInt32UpperBound_ || !hasInt32LowerBound_)
|
||||
sp.printf(" (< pow(2, %d+1))", max_exponent_);
|
||||
if (IsExponentInteresting(this)) {
|
||||
if (max_exponent_ == IncludesInfinityAndNaN)
|
||||
sp.printf(" (U inf U NaN)", max_exponent_);
|
||||
else if (max_exponent_ == IncludesInfinity)
|
||||
sp.printf(" (U inf)");
|
||||
else
|
||||
sp.printf(" (< pow(2, %d+1))", max_exponent_);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -390,11 +412,23 @@ Range::intersect(const Range *lhs, const Range *rhs, bool *emptyRange)
|
||||
// than our newLower and newUpper. This is unusual, so we handle it here
|
||||
// instead of in optimize().
|
||||
//
|
||||
// For example, when the floating-point range has an actual maximum value
|
||||
// of 1.5, it may have a range like [0,2] and the max_exponent may be zero.
|
||||
// For example, consider the range F[0,1.5]. Range analysis represents the
|
||||
// lower and upper bound as integers, so we'd actually have
|
||||
// F[0,2] (< pow(2, 0+1)). In this case, the exponent gives us a slightly
|
||||
// more precise upper bound than the integer upper bound.
|
||||
//
|
||||
// When intersecting such a range with an integer range, the fractional part
|
||||
// of the range is dropped, but the max exponent of 0 remains valid.
|
||||
if (lhs->canHaveFractionalPart_ != rhs->canHaveFractionalPart_) {
|
||||
// of the range is dropped. The max exponent of 0 remains valid, so the
|
||||
// upper bound needs to be adjusted to 1.
|
||||
//
|
||||
// When intersecting F[0,2] (< pow(2, 0+1)) with a range like F[2,4],
|
||||
// the naive intersection is I[2,2], but since the max exponent tells us
|
||||
// that the value is always less than 2, the intersection is actually empty.
|
||||
if (lhs->canHaveFractionalPart_ != rhs->canHaveFractionalPart_ ||
|
||||
(lhs->canHaveFractionalPart_ &&
|
||||
newHasInt32LowerBound && newHasInt32UpperBound &&
|
||||
newLower == newUpper))
|
||||
{
|
||||
refineInt32BoundsByExponent(newExponent, &newLower, &newUpper);
|
||||
|
||||
// If we're intersecting two ranges that don't overlap, this could also
|
||||
@ -2424,3 +2458,13 @@ MNot::collectRangeInfo()
|
||||
{
|
||||
operandIsNeverNaN_ = !Range(operand()).canBeNaN();
|
||||
}
|
||||
|
||||
void
|
||||
MPowHalf::collectRangeInfo()
|
||||
{
|
||||
Range inputRange(input());
|
||||
operandIsNeverNegativeInfinity_ = !inputRange.canBeInfiniteOrNaN() ||
|
||||
inputRange.hasInt32LowerBound();
|
||||
operandIsNeverNegativeZero_ = !inputRange.canBeZero();
|
||||
operandIsNeverNaN_ = !inputRange.canBeNaN();
|
||||
}
|
||||
|
@ -374,11 +374,16 @@ AllocationIntegrityState::dump()
|
||||
for (size_t i = 0; i < block->numPhis(); i++) {
|
||||
InstructionInfo &info = blocks[blockIndex].phis[i];
|
||||
LPhi *phi = block->getPhi(i);
|
||||
CodePosition output(phi->id(), CodePosition::OUTPUT);
|
||||
|
||||
fprintf(stderr, "Phi v%u <-", info.outputs[0].virtualRegister());
|
||||
// Don't print the inputOf for phi nodes, since it's never used.
|
||||
fprintf(stderr, "[,%u Phi [def v%u %s] <-",
|
||||
output.pos(),
|
||||
info.outputs[0].virtualRegister(),
|
||||
phi->getDef(0)->output()->toString());
|
||||
for (size_t j = 0; j < phi->numOperands(); j++)
|
||||
fprintf(stderr, " %s", info.inputs[j].toString());
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "]\n");
|
||||
}
|
||||
|
||||
for (LInstructionIterator iter = block->begin(); iter != block->end(); iter++) {
|
||||
@ -388,7 +393,10 @@ AllocationIntegrityState::dump()
|
||||
CodePosition input(ins->id(), CodePosition::INPUT);
|
||||
CodePosition output(ins->id(), CodePosition::OUTPUT);
|
||||
|
||||
fprintf(stderr, "[%u,%u %s]", input.pos(), output.pos(), ins->opName());
|
||||
fprintf(stderr, "[");
|
||||
if (input != CodePosition::MIN)
|
||||
fprintf(stderr, "%u,%u ", input.pos(), output.pos());
|
||||
fprintf(stderr, "%s]", ins->opName());
|
||||
|
||||
if (ins->isMoveGroup()) {
|
||||
LMoveGroup *group = ins->toMoveGroup();
|
||||
|
@ -328,6 +328,8 @@ class RegisterAllocator
|
||||
return CodePosition(pos, CodePosition::INPUT);
|
||||
}
|
||||
CodePosition inputOf(const LInstruction *ins) const {
|
||||
// Phi nodes "use" their inputs before the beginning of the block.
|
||||
JS_ASSERT(!ins->isPhi());
|
||||
return CodePosition(ins->id(), CodePosition::INPUT);
|
||||
}
|
||||
|
||||
@ -341,17 +343,6 @@ class RegisterAllocator
|
||||
return getMoveGroupAfter(pos.ins());
|
||||
}
|
||||
|
||||
size_t findFirstNonCallSafepoint(CodePosition from) const
|
||||
{
|
||||
size_t i = 0;
|
||||
for (; i < graph.numNonCallSafepoints(); i++) {
|
||||
const LInstruction *ins = graph.getNonCallSafepoint(i);
|
||||
if (from <= inputOf(ins))
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
CodePosition minimalDefEnd(LInstruction *ins) {
|
||||
// Compute the shortest interval that captures vregs defined by ins.
|
||||
// Watch for instructions that are followed by an OSI point and/or Nop.
|
||||
|
@ -162,20 +162,20 @@ TypeRepresentationSet::TypeRepresentationSet()
|
||||
bool
|
||||
TypeRepresentationSet::empty()
|
||||
{
|
||||
return length() == 0;
|
||||
return length_ == 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
TypeRepresentationSet::length()
|
||||
bool
|
||||
TypeRepresentationSet::singleton()
|
||||
{
|
||||
return length_;
|
||||
return length_ == 1;
|
||||
}
|
||||
|
||||
TypeRepresentation *
|
||||
TypeRepresentationSet::get(size_t i)
|
||||
TypeRepresentationSet::getTypeRepresentation()
|
||||
{
|
||||
JS_ASSERT(i < length());
|
||||
return entries_[i];
|
||||
JS_ASSERT(singleton());
|
||||
return get(0);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -55,6 +55,7 @@ class TypeRepresentationSetBuilder {
|
||||
|
||||
class TypeRepresentationSet {
|
||||
private:
|
||||
friend struct TypeRepresentationSetHasher;
|
||||
friend class TypeRepresentationSetBuilder;
|
||||
|
||||
size_t length_;
|
||||
@ -62,6 +63,14 @@ class TypeRepresentationSet {
|
||||
|
||||
TypeRepresentationSet(size_t length, TypeRepresentation **entries);
|
||||
|
||||
size_t length() const {
|
||||
return length_;
|
||||
}
|
||||
|
||||
TypeRepresentation *get(uint32_t i) const {
|
||||
return entries_[i];
|
||||
}
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Constructors
|
||||
@ -76,8 +85,7 @@ class TypeRepresentationSet {
|
||||
// Query the set
|
||||
|
||||
bool empty();
|
||||
size_t length();
|
||||
TypeRepresentation *get(size_t i);
|
||||
bool singleton();
|
||||
bool allOfKind(TypeRepresentation::Kind kind);
|
||||
|
||||
// Returns true only when non-empty and `kind()` is
|
||||
@ -99,6 +107,11 @@ class TypeRepresentationSet {
|
||||
|
||||
TypeRepresentation::Kind kind();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following operations are only valid on a singleton set:
|
||||
|
||||
TypeRepresentation *getTypeRepresentation();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Array operations
|
||||
//
|
||||
|
@ -551,19 +551,29 @@ CodeGeneratorX86Shared::visitPowHalfD(LPowHalfD *ins)
|
||||
|
||||
Label done, sqrt;
|
||||
|
||||
// Branch if not -Infinity.
|
||||
masm.loadConstantDouble(NegativeInfinity(), ScratchFloatReg);
|
||||
masm.branchDouble(Assembler::DoubleNotEqualOrUnordered, input, ScratchFloatReg, &sqrt);
|
||||
if (!ins->mir()->operandIsNeverNegativeInfinity()) {
|
||||
// Branch if not -Infinity.
|
||||
masm.loadConstantDouble(NegativeInfinity(), ScratchFloatReg);
|
||||
|
||||
// Math.pow(-Infinity, 0.5) == Infinity.
|
||||
masm.xorpd(input, input);
|
||||
masm.subsd(ScratchFloatReg, input);
|
||||
masm.jump(&done);
|
||||
Assembler::DoubleCondition cond = Assembler::DoubleNotEqualOrUnordered;
|
||||
if (ins->mir()->operandIsNeverNaN())
|
||||
cond = Assembler::DoubleNotEqual;
|
||||
masm.branchDouble(cond, input, ScratchFloatReg, &sqrt);
|
||||
|
||||
// Math.pow(-Infinity, 0.5) == Infinity.
|
||||
masm.xorpd(input, input);
|
||||
masm.subsd(ScratchFloatReg, input);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&sqrt);
|
||||
}
|
||||
|
||||
if (!ins->mir()->operandIsNeverNegativeZero()) {
|
||||
// Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5). Adding 0 converts any -0 to 0.
|
||||
masm.xorpd(ScratchFloatReg, ScratchFloatReg);
|
||||
masm.addsd(ScratchFloatReg, input);
|
||||
}
|
||||
|
||||
// Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5). Adding 0 converts any -0 to 0.
|
||||
masm.bind(&sqrt);
|
||||
masm.xorpd(ScratchFloatReg, ScratchFloatReg);
|
||||
masm.addsd(ScratchFloatReg, input);
|
||||
masm.sqrtsd(input, input);
|
||||
|
||||
masm.bind(&done);
|
||||
|
@ -171,6 +171,9 @@ class LPowHalfD : public LInstructionHelper<1, 1, 0>
|
||||
const LDefinition *output() {
|
||||
return getDef(0);
|
||||
}
|
||||
MPowHalf *mir() const {
|
||||
return mir_->toPowHalf();
|
||||
}
|
||||
};
|
||||
|
||||
// Takes a tableswitch with an integer to decide
|
||||
|
@ -1437,43 +1437,21 @@ js_QuoteString(ExclusiveContext *cx, JSString *str, jschar quote)
|
||||
static JSObject *
|
||||
GetBlockChainAtPC(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
jsbytecode *start = script->main();
|
||||
JS_ASSERT(pc >= script->main() && pc < script->code + script->length);
|
||||
|
||||
JS_ASSERT(pc >= start && pc < script->code + script->length);
|
||||
ptrdiff_t offset = pc - script->main();
|
||||
|
||||
if (!script->hasBlockScopes())
|
||||
return nullptr;
|
||||
|
||||
BlockScopeArray *blockScopes = script->blockScopes();
|
||||
JSObject *blockChain = nullptr;
|
||||
for (jsbytecode *p = start; p < pc; p += GetBytecodeLength(p)) {
|
||||
JSOp op = JSOp(*p);
|
||||
|
||||
switch (op) {
|
||||
case JSOP_ENTERBLOCK:
|
||||
case JSOP_ENTERLET0:
|
||||
case JSOP_ENTERLET1:
|
||||
case JSOP_ENTERLET2: {
|
||||
JSObject *child = script->getObject(p);
|
||||
JS_ASSERT_IF(blockChain, child->as<BlockObject>().stackDepth() >=
|
||||
blockChain->as<BlockObject>().stackDepth());
|
||||
blockChain = child;
|
||||
for (uint32_t n = 0; n < blockScopes->length; n++) {
|
||||
const BlockScopeNote *note = &blockScopes->vector[n];
|
||||
if (note->start > offset)
|
||||
break;
|
||||
}
|
||||
case JSOP_LEAVEBLOCK:
|
||||
case JSOP_LEAVEBLOCKEXPR:
|
||||
case JSOP_LEAVEFORLETIN: {
|
||||
// Some LEAVEBLOCK instructions are due to early exits via
|
||||
// return/break/etc. from block-scoped loops and functions. We
|
||||
// should ignore these instructions, since they don't really signal
|
||||
// the end of the block.
|
||||
jssrcnote *sn = js_GetSrcNote(cx, script, p);
|
||||
if (!(sn && SN_TYPE(sn) == SRC_HIDDEN)) {
|
||||
JS_ASSERT(blockChain);
|
||||
blockChain = blockChain->as<StaticBlockObject>().enclosingBlock();
|
||||
JS_ASSERT_IF(blockChain, blockChain->is<BlockObject>());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (offset <= note->start + note->length)
|
||||
blockChain = script->getObject(note->index);
|
||||
}
|
||||
|
||||
return blockChain;
|
||||
|
@ -416,7 +416,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
};
|
||||
|
||||
uint32_t length, lineno, nslots;
|
||||
uint32_t natoms, nsrcnotes, ntrynotes, nobjects, nregexps, nconsts, i;
|
||||
uint32_t natoms, nsrcnotes, i;
|
||||
uint32_t nconsts, nobjects, nregexps, ntrynotes, nblockscopes;
|
||||
uint32_t prologLength, version;
|
||||
uint32_t funLength = 0;
|
||||
uint32_t nTypeSets = 0;
|
||||
@ -424,7 +425,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
|
||||
JSContext *cx = xdr->cx();
|
||||
RootedScript script(cx);
|
||||
nsrcnotes = ntrynotes = natoms = nobjects = nregexps = nconsts = 0;
|
||||
natoms = nsrcnotes = 0;
|
||||
nconsts = nobjects = nregexps = ntrynotes = nblockscopes = 0;
|
||||
|
||||
/* XDR arguments and vars. */
|
||||
uint16_t nargs = 0, nvars = 0;
|
||||
@ -468,6 +470,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
nregexps = script->regexps()->length;
|
||||
if (script->hasTrynotes())
|
||||
ntrynotes = script->trynotes()->length;
|
||||
if (script->hasBlockScopes())
|
||||
nblockscopes = script->blockScopes()->length;
|
||||
|
||||
nTypeSets = script->nTypeSets;
|
||||
funLength = script->funLength;
|
||||
@ -512,21 +516,20 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
if (!xdr->codeUint32(&version))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* To fuse allocations, we need srcnote, atom, objects, regexp, and trynote
|
||||
* counts early.
|
||||
*/
|
||||
// To fuse allocations, we need lengths of all embedded arrays early.
|
||||
if (!xdr->codeUint32(&natoms))
|
||||
return false;
|
||||
if (!xdr->codeUint32(&nsrcnotes))
|
||||
return false;
|
||||
if (!xdr->codeUint32(&ntrynotes))
|
||||
if (!xdr->codeUint32(&nconsts))
|
||||
return false;
|
||||
if (!xdr->codeUint32(&nobjects))
|
||||
return false;
|
||||
if (!xdr->codeUint32(&nregexps))
|
||||
return false;
|
||||
if (!xdr->codeUint32(&nconsts))
|
||||
if (!xdr->codeUint32(&ntrynotes))
|
||||
return false;
|
||||
if (!xdr->codeUint32(&nblockscopes))
|
||||
return false;
|
||||
if (!xdr->codeUint32(&nTypeSets))
|
||||
return false;
|
||||
@ -569,8 +572,11 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
return false;
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
if (!JSScript::partiallyInit(cx, script, nobjects, nregexps, ntrynotes, nconsts, nTypeSets))
|
||||
if (!JSScript::partiallyInit(cx, script, nconsts, nobjects, nregexps, ntrynotes,
|
||||
nblockscopes, nTypeSets))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
JS_ASSERT(!script->mainOffset);
|
||||
script->mainOffset = prologLength;
|
||||
@ -664,6 +670,14 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nconsts) {
|
||||
HeapValue *vector = script->consts()->vector;
|
||||
for (i = 0; i != nconsts; ++i) {
|
||||
if (!XDRScriptConst(xdr, &vector[i]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Here looping from 0-to-length to xdr objects is essential to ensure that
|
||||
* all references to enclosing blocks (via FindBlockIndex below) happen
|
||||
@ -740,6 +754,7 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
*objp = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i != nregexps; ++i) {
|
||||
if (!XDRScriptRegExpObject(xdr, &script->regexps()->vector[i]))
|
||||
return false;
|
||||
@ -776,11 +791,13 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
} while (tn != tnfirst);
|
||||
}
|
||||
|
||||
if (nconsts) {
|
||||
HeapValue *vector = script->consts()->vector;
|
||||
for (i = 0; i != nconsts; ++i) {
|
||||
if (!XDRScriptConst(xdr, &vector[i]))
|
||||
return false;
|
||||
for (i = 0; i < nblockscopes; ++i) {
|
||||
BlockScopeNote *note = &script->blockScopes()->vector[i];
|
||||
if (!xdr->codeUint32(¬e->index) ||
|
||||
!xdr->codeUint32(¬e->start) ||
|
||||
!xdr->codeUint32(¬e->length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1580,6 +1597,7 @@ js::FreeScriptData(JSRuntime *rt)
|
||||
* ObjectArray Objects objects()
|
||||
* ObjectArray Regexps regexps()
|
||||
* TryNoteArray Try notes trynotes()
|
||||
* BlockScopeArray Scope notes blockScopes()
|
||||
*
|
||||
* Then are the elements of several arrays.
|
||||
* - Most of these arrays have headers listed above (if present). For each of
|
||||
@ -1595,6 +1613,7 @@ js::FreeScriptData(JSRuntime *rt)
|
||||
* Objects objects()->vector objects()->length
|
||||
* Regexps regexps()->vector regexps()->length
|
||||
* Try notes trynotes()->vector trynotes()->length
|
||||
* Scope notes blockScopes()->vector blockScopes()->length
|
||||
*
|
||||
* IMPORTANT: This layout has two key properties.
|
||||
* - It ensures that everything has sufficient alignment; in particular, the
|
||||
@ -1640,6 +1659,7 @@ js::FreeScriptData(JSRuntime *rt)
|
||||
JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ConstArray));
|
||||
JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ObjectArray)); /* there are two of these */
|
||||
JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(TryNoteArray));
|
||||
JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(BlockScopeArray));
|
||||
|
||||
/* These assertions ensure there is no padding required between array elements. */
|
||||
JS_STATIC_ASSERT(HAS_JSVAL_ALIGNMENT(HeapValue));
|
||||
@ -1649,9 +1669,15 @@ JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, JSTryNote));
|
||||
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(JSTryNote, uint32_t));
|
||||
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(uint32_t, uint32_t));
|
||||
|
||||
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapValue, BlockScopeNote));
|
||||
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(BlockScopeNote, BlockScopeNote));
|
||||
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(JSTryNote, BlockScopeNote));
|
||||
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, BlockScopeNote));
|
||||
JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(BlockScopeNote, uint32_t));
|
||||
|
||||
static inline size_t
|
||||
ScriptDataSize(uint32_t nbindings, uint32_t nobjects, uint32_t nregexps,
|
||||
uint32_t ntrynotes, uint32_t nconsts)
|
||||
ScriptDataSize(uint32_t nbindings, uint32_t nconsts, uint32_t nobjects, uint32_t nregexps,
|
||||
uint32_t ntrynotes, uint32_t nblockscopes)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
@ -1663,6 +1689,8 @@ ScriptDataSize(uint32_t nbindings, uint32_t nobjects, uint32_t nregexps,
|
||||
size += sizeof(ObjectArray) + nregexps * sizeof(JSObject *);
|
||||
if (ntrynotes != 0)
|
||||
size += sizeof(TryNoteArray) + ntrynotes * sizeof(JSTryNote);
|
||||
if (nblockscopes != 0)
|
||||
size += sizeof(BlockScopeArray) + nblockscopes * sizeof(BlockScopeNote);
|
||||
|
||||
if (nbindings != 0) {
|
||||
// Make sure bindings are sufficiently aligned.
|
||||
@ -1736,10 +1764,12 @@ AllocScriptData(ExclusiveContext *cx, size_t size)
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nobjects,
|
||||
uint32_t nregexps, uint32_t ntrynotes, uint32_t nconsts, uint32_t nTypeSets)
|
||||
JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nconsts,
|
||||
uint32_t nobjects, uint32_t nregexps, uint32_t ntrynotes,
|
||||
uint32_t nblockscopes, uint32_t nTypeSets)
|
||||
{
|
||||
size_t size = ScriptDataSize(script->bindings.count(), nobjects, nregexps, ntrynotes, nconsts);
|
||||
size_t size = ScriptDataSize(script->bindings.count(), nconsts, nobjects, nregexps, ntrynotes,
|
||||
nblockscopes);
|
||||
script->data = AllocScriptData(cx, size);
|
||||
if (!script->data)
|
||||
return false;
|
||||
@ -1765,6 +1795,10 @@ JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nobj
|
||||
script->setHasArray(TRYNOTES);
|
||||
cursor += sizeof(TryNoteArray);
|
||||
}
|
||||
if (nblockscopes != 0) {
|
||||
script->setHasArray(BLOCK_SCOPES);
|
||||
cursor += sizeof(BlockScopeArray);
|
||||
}
|
||||
|
||||
if (nconsts != 0) {
|
||||
JS_ASSERT(reinterpret_cast<uintptr_t>(cursor) % sizeof(jsval) == 0);
|
||||
@ -1795,6 +1829,16 @@ JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nobj
|
||||
cursor += vectorSize;
|
||||
}
|
||||
|
||||
if (nblockscopes != 0) {
|
||||
script->blockScopes()->length = nblockscopes;
|
||||
script->blockScopes()->vector = reinterpret_cast<BlockScopeNote *>(cursor);
|
||||
size_t vectorSize = nblockscopes * sizeof(script->blockScopes()->vector[0]);
|
||||
#ifdef DEBUG
|
||||
memset(cursor, 0, vectorSize);
|
||||
#endif
|
||||
cursor += vectorSize;
|
||||
}
|
||||
|
||||
if (script->bindings.count() != 0) {
|
||||
// Make sure bindings are sufficiently aligned.
|
||||
cursor = reinterpret_cast<uint8_t*>
|
||||
@ -1809,7 +1853,7 @@ JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nobj
|
||||
/* static */ bool
|
||||
JSScript::fullyInitTrivial(ExclusiveContext *cx, Handle<JSScript*> script)
|
||||
{
|
||||
if (!partiallyInit(cx, script, 0, 0, 0, 0, 0))
|
||||
if (!partiallyInit(cx, script, 0, 0, 0, 0, 0, 0))
|
||||
return false;
|
||||
|
||||
SharedScriptData *ssd = SharedScriptData::new_(cx, 1, 1, 0);
|
||||
@ -1835,8 +1879,8 @@ JSScript::fullyInitFromEmitter(ExclusiveContext *cx, HandleScript script, Byteco
|
||||
uint32_t nsrcnotes = uint32_t(bce->countFinalSourceNotes());
|
||||
uint32_t natoms = bce->atomIndices->count();
|
||||
if (!partiallyInit(cx, script,
|
||||
bce->objectList.length, bce->regexpList.length, bce->tryNoteList.length(),
|
||||
bce->constList.length(), bce->typesetCount))
|
||||
bce->constList.length(), bce->objectList.length, bce->regexpList.length,
|
||||
bce->tryNoteList.length(), bce->blockScopeList.length(), bce->typesetCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1873,14 +1917,16 @@ JSScript::fullyInitFromEmitter(ExclusiveContext *cx, HandleScript script, Byteco
|
||||
|
||||
FunctionBox *funbox = bce->sc->isFunctionBox() ? bce->sc->asFunctionBox() : nullptr;
|
||||
|
||||
if (bce->tryNoteList.length() != 0)
|
||||
bce->tryNoteList.finish(script->trynotes());
|
||||
if (bce->constList.length() != 0)
|
||||
bce->constList.finish(script->consts());
|
||||
if (bce->objectList.length != 0)
|
||||
bce->objectList.finish(script->objects());
|
||||
if (bce->regexpList.length != 0)
|
||||
bce->regexpList.finish(script->regexps());
|
||||
if (bce->constList.length() != 0)
|
||||
bce->constList.finish(script->consts());
|
||||
if (bce->tryNoteList.length() != 0)
|
||||
bce->tryNoteList.finish(script->trynotes());
|
||||
if (bce->blockScopeList.length() != 0)
|
||||
bce->blockScopeList.finish(script->blockScopes());
|
||||
script->strict = bce->sc->strict;
|
||||
script->explicitUseStrict = bce->sc->hasExplicitUseStrict();
|
||||
script->bindingsAccessedDynamically = bce->sc->bindingsAccessedDynamically();
|
||||
@ -2279,6 +2325,7 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
uint32_t nobjects = src->hasObjects() ? src->objects()->length : 0;
|
||||
uint32_t nregexps = src->hasRegexps() ? src->regexps()->length : 0;
|
||||
uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
|
||||
uint32_t nblockscopes = src->hasBlockScopes() ? src->blockScopes()->length : 0;
|
||||
|
||||
/* Script data */
|
||||
|
||||
@ -2444,6 +2491,8 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
}
|
||||
if (ntrynotes != 0)
|
||||
dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
|
||||
if (nblockscopes != 0)
|
||||
dst->blockScopes()->vector = Rebase<BlockScopeNote>(dst, src, src->blockScopes()->vector);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
@ -81,19 +81,31 @@ struct JSTryNote {
|
||||
|
||||
namespace js {
|
||||
|
||||
struct BlockScopeNote {
|
||||
uint32_t index; // Index of StaticScopeObject in the object array.
|
||||
uint32_t start; // Bytecode offset at which this scope starts.
|
||||
uint32_t length; // Bytecode length of scope.
|
||||
uint32_t padding; // Pad to 64-bit boundary.
|
||||
};
|
||||
|
||||
struct ConstArray {
|
||||
js::HeapValue *vector; /* array of indexed constant values */
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
struct ObjectArray {
|
||||
js::HeapPtrObject *vector; /* array of indexed objects */
|
||||
uint32_t length; /* count of indexed objects */
|
||||
js::HeapPtrObject *vector; // Array of indexed objects.
|
||||
uint32_t length; // Count of indexed objects.
|
||||
};
|
||||
|
||||
struct TryNoteArray {
|
||||
JSTryNote *vector; /* array of indexed try notes */
|
||||
uint32_t length; /* count of indexed try notes */
|
||||
JSTryNote *vector; // Array of indexed try notes.
|
||||
uint32_t length; // Count of indexed try notes.
|
||||
};
|
||||
|
||||
struct BlockScopeArray {
|
||||
BlockScopeNote *vector; // Array of indexed BlockScopeNote records.
|
||||
uint32_t length; // Count of indexed try notes.
|
||||
};
|
||||
|
||||
/*
|
||||
@ -552,6 +564,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
||||
OBJECTS,
|
||||
REGEXPS,
|
||||
TRYNOTES,
|
||||
BLOCK_SCOPES,
|
||||
ARRAY_KIND_BITS
|
||||
};
|
||||
|
||||
@ -564,7 +577,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
||||
uint8_t generatorKindBits_:2;
|
||||
|
||||
// Unused padding; feel free to steal these if you need them.
|
||||
uint8_t padToByte_:2;
|
||||
uint8_t padToByte_:1;
|
||||
|
||||
// 1-bit fields.
|
||||
|
||||
@ -650,8 +663,9 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
||||
// successfully creating any kind (function or other) of new JSScript.
|
||||
// However, callers of fullyInitFromEmitter() do not need to do this.
|
||||
static bool partiallyInit(js::ExclusiveContext *cx, JS::Handle<JSScript*> script,
|
||||
uint32_t nobjects, uint32_t nregexps,
|
||||
uint32_t ntrynotes, uint32_t nconsts, uint32_t nTypeSets);
|
||||
uint32_t nconsts, uint32_t nobjects, uint32_t nregexps,
|
||||
uint32_t ntrynotes, uint32_t nblockscopes,
|
||||
uint32_t nTypeSets);
|
||||
static bool fullyInitFromEmitter(js::ExclusiveContext *cx, JS::Handle<JSScript*> script,
|
||||
js::frontend::BytecodeEmitter *bce);
|
||||
// Initialize a no-op script.
|
||||
@ -913,6 +927,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
||||
bool hasObjects() { return hasArray(OBJECTS); }
|
||||
bool hasRegexps() { return hasArray(REGEXPS); }
|
||||
bool hasTrynotes() { return hasArray(TRYNOTES); }
|
||||
bool hasBlockScopes() { return hasArray(BLOCK_SCOPES); }
|
||||
|
||||
#define OFF(fooOff, hasFoo, t) (fooOff() + (hasFoo() ? sizeof(t) : 0))
|
||||
|
||||
@ -920,6 +935,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
||||
size_t objectsOffset() { return OFF(constsOffset, hasConsts, js::ConstArray); }
|
||||
size_t regexpsOffset() { return OFF(objectsOffset, hasObjects, js::ObjectArray); }
|
||||
size_t trynotesOffset() { return OFF(regexpsOffset, hasRegexps, js::ObjectArray); }
|
||||
size_t blockScopesOffset(){ return OFF(trynotesOffset, hasTrynotes, js::TryNoteArray); }
|
||||
|
||||
js::ConstArray *consts() {
|
||||
JS_ASSERT(hasConsts());
|
||||
@ -941,6 +957,11 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
||||
return reinterpret_cast<js::TryNoteArray *>(data + trynotesOffset());
|
||||
}
|
||||
|
||||
js::BlockScopeArray *blockScopes() {
|
||||
JS_ASSERT(hasBlockScopes());
|
||||
return reinterpret_cast<js::BlockScopeArray *>(data + blockScopesOffset());
|
||||
}
|
||||
|
||||
bool hasLoops();
|
||||
|
||||
js::HeapPtrAtom &getAtom(size_t index) const {
|
||||
|
@ -5796,6 +5796,10 @@ main(int argc, char **argv, char **envp)
|
||||
"(default: 10)", -1)
|
||||
|| !op.addBoolOption('\0', "no-fpu", "Pretend CPU does not support floating-point operations "
|
||||
"to test JIT codegen (no-op on platforms other than x86).")
|
||||
|| !op.addBoolOption('\0', "no-sse3", "Pretend CPU does not support SSE3 instructions and above "
|
||||
"to test JIT codegen (no-op on platforms other than x86 and x64).")
|
||||
|| !op.addBoolOption('\0', "no-sse4", "Pretend CPU does not support SSE4 instructions"
|
||||
"to test JIT codegen (no-op on platforms other than x86 and x64).")
|
||||
|| !op.addBoolOption('\0', "fuzzing-safe", "Don't expose functions that aren't safe for "
|
||||
"fuzzers to call")
|
||||
#ifdef DEBUG
|
||||
@ -5840,6 +5844,17 @@ main(int argc, char **argv, char **envp)
|
||||
if (op.getBoolOption("no-fpu"))
|
||||
JSC::MacroAssembler::SetFloatingPointDisabled();
|
||||
#endif
|
||||
|
||||
#if (defined(JS_CPU_X86) || defined(JS_CPU_X64)) && defined(JS_ION)
|
||||
if (op.getBoolOption("no-sse3")) {
|
||||
JSC::MacroAssembler::SetSSE3Disabled();
|
||||
PropagateFlagToNestedShells("--no-sse3");
|
||||
}
|
||||
if (op.getBoolOption("no-sse4")) {
|
||||
JSC::MacroAssembler::SetSSE4Disabled();
|
||||
PropagateFlagToNestedShells("--no-sse4");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Start the engine.
|
||||
|
61
js/src/tests/ecma_6/TypedObject/redimension.js
Normal file
61
js/src/tests/ecma_6/TypedObject/redimension.js
Normal 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();
|
||||
|
||||
|
@ -1660,7 +1660,7 @@ CASE(JSOP_RETRVAL)
|
||||
if (!REGS.fp()->isYielding())
|
||||
REGS.fp()->epilogue(cx);
|
||||
else
|
||||
probes::ExitScript(cx, script, script->function(), REGS.fp());
|
||||
probes::ExitScript(cx, script, script->function(), REGS.fp()->hasPushedSPSFrame());
|
||||
|
||||
#if defined(JS_ION)
|
||||
jit_return_pop_frame:
|
||||
@ -3437,7 +3437,7 @@ DEFAULT()
|
||||
if (!REGS.fp()->isYielding())
|
||||
REGS.fp()->epilogue(cx);
|
||||
else
|
||||
probes::ExitScript(cx, script, script->function(), REGS.fp());
|
||||
probes::ExitScript(cx, script, script->function(), REGS.fp()->hasPushedSPSFrame());
|
||||
|
||||
gc::MaybeVerifyBarriers(cx, true);
|
||||
|
||||
|
@ -63,8 +63,7 @@ probes::EnterScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
}
|
||||
|
||||
inline bool
|
||||
probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
AbstractFramePtr fp)
|
||||
probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun, bool popSPSFrame)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
@ -76,22 +75,10 @@ probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
cx->doFunctionCallback(maybeFun, script, 0);
|
||||
#endif
|
||||
|
||||
JSRuntime *rt = cx->runtime();
|
||||
/*
|
||||
* Coming from IonMonkey, the fp might not be known (fp == nullptr), but
|
||||
* IonMonkey will only call exitScript() when absolutely necessary, so it is
|
||||
* guaranteed that fp->hasPushedSPSFrame() would have been true
|
||||
*/
|
||||
if ((!fp && rt->spsProfiler.enabled()) || (fp && fp.hasPushedSPSFrame()))
|
||||
rt->spsProfiler.exit(cx, script, maybeFun);
|
||||
return ok;
|
||||
}
|
||||
if (popSPSFrame)
|
||||
cx->runtime()->spsProfiler.exit(cx, script, maybeFun);
|
||||
|
||||
inline bool
|
||||
probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
StackFrame *fp)
|
||||
{
|
||||
return probes::ExitScript(cx, script, maybeFun, fp ? AbstractFramePtr(fp) : AbstractFramePtr());
|
||||
return ok;
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -69,8 +69,7 @@ bool WantNativeAddressInfo(JSContext *);
|
||||
bool EnterScript(JSContext *, JSScript *, JSFunction *, StackFrame *);
|
||||
|
||||
/* About to leave a JS function */
|
||||
bool ExitScript(JSContext *, JSScript *, JSFunction *, AbstractFramePtr);
|
||||
bool ExitScript(JSContext *, JSScript *, JSFunction *, StackFrame *);
|
||||
bool ExitScript(JSContext *, JSScript *, JSFunction *, bool popSPSFrame);
|
||||
|
||||
/* Executing a script */
|
||||
bool StartExecution(JSScript *script);
|
||||
|
@ -300,7 +300,7 @@ StackFrame::epilogue(JSContext *cx)
|
||||
JS_ASSERT(!hasBlockChain());
|
||||
|
||||
RootedScript script(cx, this->script());
|
||||
probes::ExitScript(cx, script, script->function(), this);
|
||||
probes::ExitScript(cx, script, script->function(), hasPushedSPSFrame());
|
||||
|
||||
if (isEvalFrame()) {
|
||||
if (isStrictEvalFrame()) {
|
||||
|
@ -22,7 +22,7 @@ namespace js {
|
||||
* and saved versions. If deserialization fails, the data should be
|
||||
* invalidated if possible.
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 153);
|
||||
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 154);
|
||||
|
||||
class XDRBuffer {
|
||||
public:
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
#include "nsXULAppAPI.h"
|
||||
#ifdef XP_MACOSX
|
||||
@ -38,8 +39,8 @@ main(int argc, char** argv, char** envp)
|
||||
setbuf(stdout, 0);
|
||||
#endif
|
||||
|
||||
#ifdef XRE_HAS_DLL_BLOCKLIST
|
||||
XRE_SetupDllBlocklist();
|
||||
#ifdef HAS_DLL_BLOCKLIST
|
||||
DllBlocklist_Initialize();
|
||||
#endif
|
||||
|
||||
int result = XRE_XPCShellMain(argc, argv, envp);
|
||||
|
16
layout/base/crashtests/806056-1.html
Normal file
16
layout/base/crashtests/806056-1.html
Normal 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>
|
18
layout/base/crashtests/806056-2.html
Normal file
18
layout/base/crashtests/806056-2.html
Normal 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>
|
@ -403,6 +403,8 @@ load 788360.html
|
||||
load 793848.html
|
||||
load 795646.html
|
||||
skip-if(1) load 802902.html # bug 901752
|
||||
load 806056-1.html
|
||||
load 806056-2.html
|
||||
load 813372-1.html
|
||||
asserts-if(gtk2Widget,0-1) load 822865.html # bug 540078
|
||||
load 833604-1.html
|
||||
|
@ -3455,6 +3455,9 @@ PresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent,
|
||||
if (!targetView)
|
||||
return;
|
||||
targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
|
||||
if (MOZ_UNLIKELY(mIsDestroying)) {
|
||||
return;
|
||||
}
|
||||
if (aFlushOnHoverChange &&
|
||||
hoverGenerationBefore != restyleManager->GetHoverGeneration()) {
|
||||
// Flush so that the resulting reflow happens now so that our caller
|
||||
|
@ -600,8 +600,10 @@ protected:
|
||||
}
|
||||
}
|
||||
virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE {
|
||||
if (mPresShell)
|
||||
mPresShell->ProcessSynthMouseMoveEvent(mFromScroll);
|
||||
if (mPresShell) {
|
||||
nsRefPtr<PresShell> shell = mPresShell;
|
||||
shell->ProcessSynthMouseMoveEvent(mFromScroll);
|
||||
}
|
||||
}
|
||||
private:
|
||||
PresShell* mPresShell;
|
||||
|
40
layout/generic/crashtests/463785.xhtml
Normal file
40
layout/generic/crashtests/463785.xhtml
Normal 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>
|
21
layout/generic/crashtests/489477.html
Normal file
21
layout/generic/crashtests/489477.html
Normal 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>
|
||||
|
11
layout/generic/crashtests/537645.xhtml
Normal file
11
layout/generic/crashtests/537645.xhtml
Normal 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>
|
24
layout/generic/crashtests/654002-1.html
Normal file
24
layout/generic/crashtests/654002-1.html
Normal 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>
|
26
layout/generic/crashtests/654002-2.html
Normal file
26
layout/generic/crashtests/654002-2.html
Normal 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>
|
28
layout/generic/crashtests/777838.html
Normal file
28
layout/generic/crashtests/777838.html
Normal 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>
|
||||
|
17
layout/generic/crashtests/784600.html
Normal file
17
layout/generic/crashtests/784600.html
Normal 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>
|
@ -136,6 +136,7 @@ load 387233-1.html
|
||||
load 387233-2.html
|
||||
load 387282-1.html
|
||||
load 388175-1.html
|
||||
load 388367-1.html
|
||||
load 388709-1.html
|
||||
load 389635-1.html
|
||||
load 390050-1.html
|
||||
@ -169,7 +170,7 @@ load 398322-1.html
|
||||
load 398322-2.html
|
||||
load 398332-1.html
|
||||
load 398332-2.html
|
||||
asserts(2) load 398332-3.html # bug 436123 and bug 457397
|
||||
asserts(0-2) load 398332-3.html # bug 436123 and bug 457397
|
||||
load 399407-1.xhtml
|
||||
load 399412-1.html
|
||||
load 399843-1.html
|
||||
@ -302,6 +303,7 @@ load 463350-1.html
|
||||
load 463350-2.html
|
||||
load 463350-3.html
|
||||
load 463741-1.html
|
||||
load 463785.xhtml
|
||||
load 465651-1.html
|
||||
load 467137-1.html
|
||||
load 467213-1.html
|
||||
@ -331,6 +333,7 @@ asserts-if(!Android,1) load 479938-1.html # Bug 575011
|
||||
load 480345-1.html
|
||||
skip-if(Android) load 481921.html
|
||||
load 489462-1.html
|
||||
load 489477.html
|
||||
load 489480-1.xhtml
|
||||
load 493111-1.html
|
||||
load 493118-1.html
|
||||
@ -373,6 +376,7 @@ load 534082-1.html
|
||||
load 534366-1.html
|
||||
load 534366-2.html
|
||||
load 536692-1.xhtml
|
||||
load 537645.xhtml
|
||||
load 541277-1.html
|
||||
load 541277-2.html
|
||||
load 541714-1.html
|
||||
@ -421,6 +425,8 @@ load 646561-1.html
|
||||
load 646983-1.html
|
||||
load 647332-1.html
|
||||
load 650499-1.html
|
||||
load 654002-1.html
|
||||
load 654002-2.html
|
||||
load 655462-1.html
|
||||
load 656130-1.html
|
||||
load 656130-2.html
|
||||
@ -464,6 +470,8 @@ asserts(0-200) load 767765.html # bug 407550, bug 871758, and various nscoord_MA
|
||||
load 769303-1.html
|
||||
load 769303-2.html
|
||||
load 769120.html
|
||||
load 777838.html
|
||||
load 784600.html
|
||||
load 786740-1.html
|
||||
asserts(0-4) test-pref(font.size.inflation.emPerLine,15) load 791601.xhtml # 3 counts of bug 871327, 1 bug 367185
|
||||
test-pref(font.size.inflation.minTwips,120) load 794693.html
|
||||
|
BIN
layout/generic/crashtests/simple_blank.swf
Normal file
BIN
layout/generic/crashtests/simple_blank.swf
Normal file
Binary file not shown.
@ -758,7 +758,6 @@ fails == 387344-1.html 387344-1-ref.html # scrolling rowgroups were removed in b
|
||||
== 387876-3a.html 387876-3-ref.html
|
||||
== 387876-3b.html 387876-3-ref.html
|
||||
== 388026-1.html 388026-1-ref.html
|
||||
== 388367-1.html about:blank
|
||||
== 389074-1.html 389074-1-ref.html
|
||||
== 389224-1.html 389224-1-ref.html
|
||||
== 389224-2.html about:blank
|
||||
|
@ -34,30 +34,33 @@ def main():
|
||||
(options, args) = parser.parse_args()
|
||||
min_sdk_version = args[0]
|
||||
|
||||
job = subprocess.Popen(['xcode-select', '-print-path'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
out, err = job.communicate()
|
||||
if job.returncode != 0:
|
||||
print >>sys.stderr, out
|
||||
print >>sys.stderr, err
|
||||
raise Exception(('Error %d running xcode-select, you might have to run '
|
||||
'|sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer| '
|
||||
'if you are using Xcode 4.') % job.returncode)
|
||||
# The Developer folder moved in Xcode 4.3.
|
||||
xcode43_sdk_path = os.path.join(
|
||||
if sys.platform == 'darwin':
|
||||
job = subprocess.Popen(['xcode-select', '-print-path'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
out, err = job.communicate()
|
||||
if job.returncode != 0:
|
||||
print >>sys.stderr, out
|
||||
print >>sys.stderr, err
|
||||
raise Exception(('Error %d running xcode-select, you might have to run '
|
||||
'|sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer| '
|
||||
'if you are using Xcode 4.') % job.returncode)
|
||||
# The Developer folder moved in Xcode 4.3.
|
||||
xcode43_sdk_path = os.path.join(
|
||||
out.rstrip(), 'Platforms/MacOSX.platform/Developer/SDKs')
|
||||
if os.path.isdir(xcode43_sdk_path):
|
||||
sdk_dir = xcode43_sdk_path
|
||||
if os.path.isdir(xcode43_sdk_path):
|
||||
sdk_dir = xcode43_sdk_path
|
||||
else:
|
||||
sdk_dir = os.path.join(out.rstrip(), 'SDKs')
|
||||
sdks = [re.findall('^MacOSX(10\.\d+)\.sdk$', s) for s in os.listdir(sdk_dir)]
|
||||
sdks = [s[0] for s in sdks if s] # [['10.5'], ['10.6']] => ['10.5', '10.6']
|
||||
sdks = [s for s in sdks # ['10.5', '10.6'] => ['10.6']
|
||||
if parse_version(s) >= parse_version(min_sdk_version)]
|
||||
if not sdks:
|
||||
raise Exception('No %s+ SDK found' % min_sdk_version)
|
||||
best_sdk = sorted(sdks, key=parse_version)[0]
|
||||
else:
|
||||
sdk_dir = os.path.join(out.rstrip(), 'SDKs')
|
||||
sdks = [re.findall('^MacOSX(10\.\d+)\.sdk$', s) for s in os.listdir(sdk_dir)]
|
||||
sdks = [s[0] for s in sdks if s] # [['10.5'], ['10.6']] => ['10.5', '10.6']
|
||||
sdks = [s for s in sdks # ['10.5', '10.6'] => ['10.6']
|
||||
if parse_version(s) >= parse_version(min_sdk_version)]
|
||||
if not sdks:
|
||||
raise Exception('No %s+ SDK found' % min_sdk_version)
|
||||
best_sdk = sorted(sdks, key=parse_version)[0]
|
||||
best_sdk = ""
|
||||
|
||||
if options.verify and best_sdk != min_sdk_version and not options.sdk_path:
|
||||
print >>sys.stderr, ''
|
||||
@ -77,6 +80,4 @@ def main():
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if sys.platform != 'darwin':
|
||||
raise Exception("This script only runs on Mac")
|
||||
print main()
|
||||
|
@ -45,7 +45,14 @@ ifneq (,$(filter -DEFAULTLIB:mozcrt,$(MOZ_GLUE_LDFLAGS)))
|
||||
NO_INSTALL_IMPORT_LIBRARY = 1
|
||||
endif
|
||||
|
||||
EXTRA_DSO_LDOPTS += $(MOZ_ZLIB_LIBS)
|
||||
|
||||
EXTRA_DSO_LDOPTS += \
|
||||
$(MOZ_ZLIB_LIBS) \
|
||||
version.lib \
|
||||
$(NULL)
|
||||
|
||||
STL_FLAGS=
|
||||
|
||||
endif
|
||||
|
||||
ifeq (Darwin_1,$(OS_TARGET)_$(MOZ_REPLACE_MALLOC))
|
||||
|
@ -5,18 +5,15 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#include <io.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4275 4530 ) // See msvc-stl-wrapper.template.h
|
||||
#include <map>
|
||||
#pragma warning( pop )
|
||||
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#define MOZ_NO_MOZALLOC
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "prlog.h"
|
||||
|
||||
#include "nsWindowsDllInterceptor.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
@ -24,10 +21,6 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
|
||||
#define ALL_VERSIONS ((unsigned long long)-1LL)
|
||||
|
||||
// DLLs sometimes ship without a version number, particularly early
|
||||
@ -153,7 +146,47 @@ static DllBlockInfo sWindowsDllBlocklist[] = {
|
||||
// define this for very verbose dll load debug spew
|
||||
#undef DEBUG_very_verbose
|
||||
|
||||
extern bool gInXPCOMLoadOnMainThread;
|
||||
static const char kBlockedDllsParameter[] = "BlockedDllList=";
|
||||
static const int kBlockedDllsParameterLen =
|
||||
sizeof(kBlockedDllsParameter) - 1;
|
||||
|
||||
static const char kBlocklistInitFailedParameter[] = "BlocklistInitFailed=";
|
||||
static const int kBlocklistInitFailedParameterLen =
|
||||
sizeof(kBlocklistInitFailedParameter) - 1;
|
||||
|
||||
static const char kUser32BeforeBlocklistParameter[] = "User32BeforeBlocklist=";
|
||||
static const int kUser32BeforeBlocklistParameterLen =
|
||||
sizeof(kUser32BeforeBlocklistParameterLen) - 1;
|
||||
|
||||
static DWORD sThreadLoadingXPCOMModule;
|
||||
static bool sBlocklistInitFailed;
|
||||
static bool sUser32BeforeBlocklist;
|
||||
|
||||
// Duplicated from xpcom glue. Ideally this should be shared.
|
||||
static void
|
||||
printf_stderr(const char *fmt, ...)
|
||||
{
|
||||
if (IsDebuggerPresent()) {
|
||||
char buf[2048];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
va_end(args);
|
||||
OutputDebugStringA(buf);
|
||||
}
|
||||
|
||||
FILE *fp = _fdopen(_dup(2), "a");
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(fp, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
@ -170,7 +203,7 @@ struct RVAMap {
|
||||
DWORD alignedOffset = (offset / info.dwAllocationGranularity) *
|
||||
info.dwAllocationGranularity;
|
||||
|
||||
NS_ASSERTION(offset - alignedOffset < info.dwAllocationGranularity, "Wtf");
|
||||
MOZ_ASSERT(offset - alignedOffset < info.dwAllocationGranularity, "Wtf");
|
||||
|
||||
mRealView = ::MapViewOfFile(map, FILE_MAP_READ, 0, alignedOffset,
|
||||
sizeof(T) + (offset - alignedOffset));
|
||||
@ -544,7 +577,7 @@ continue_loading:
|
||||
printf_stderr("LdrLoadDll: continuing load... ('%S')\n", moduleFileName->Buffer);
|
||||
#endif
|
||||
|
||||
if (gInXPCOMLoadOnMainThread && NS_IsMainThread()) {
|
||||
if (GetCurrentThreadId() == sThreadLoadingXPCOMModule) {
|
||||
// Check to ensure that the DLL has ASLR.
|
||||
full_fname = getFullPath(filePath, fname);
|
||||
if (!full_fname) {
|
||||
@ -566,31 +599,56 @@ WindowsDllInterceptor NtDllIntercept;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void
|
||||
XRE_SetupDllBlocklist()
|
||||
NS_EXPORT void
|
||||
DllBlocklist_Initialize()
|
||||
{
|
||||
if (GetModuleHandleA("user32.dll")) {
|
||||
sUser32BeforeBlocklist = true;
|
||||
}
|
||||
|
||||
NtDllIntercept.Init("ntdll.dll");
|
||||
|
||||
ReentrancySentinel::InitializeStatics();
|
||||
|
||||
bool ok = NtDllIntercept.AddHook("LdrLoadDll", reinterpret_cast<intptr_t>(patched_LdrLoadDll), (void**) &stub_LdrLoadDll);
|
||||
|
||||
if (!ok) {
|
||||
sBlocklistInitFailed = true;
|
||||
#ifdef DEBUG
|
||||
if (!ok)
|
||||
printf_stderr ("LdrLoadDll hook failed, no dll blocklisting active\n");
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
if (!ok) {
|
||||
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DllBlockList Failed\n"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
void
|
||||
CrashReporter::WriteBlockedDlls(HANDLE file)
|
||||
NS_EXPORT void
|
||||
DllBlocklist_SetInXPCOMLoadOnMainThread(bool inXPCOMLoadOnMainThread)
|
||||
{
|
||||
DllBlockSet::Write(file);
|
||||
if (inXPCOMLoadOnMainThread) {
|
||||
MOZ_ASSERT(sThreadLoadingXPCOMModule == 0, "Only one thread should be doing this");
|
||||
sThreadLoadingXPCOMModule = GetCurrentThreadId();
|
||||
} else {
|
||||
sThreadLoadingXPCOMModule = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NS_EXPORT void
|
||||
DllBlocklist_WriteNotes(HANDLE file)
|
||||
{
|
||||
DWORD nBytes;
|
||||
|
||||
WriteFile(file, kBlockedDllsParameter, kBlockedDllsParameterLen, &nBytes, nullptr);
|
||||
DllBlockSet::Write(file);
|
||||
WriteFile(file, "\n", 1, &nBytes, nullptr);
|
||||
|
||||
if (sBlocklistInitFailed) {
|
||||
WriteFile(file, kBlocklistInitFailedParameter,
|
||||
kBlocklistInitFailedParameterLen, &nBytes, nullptr);
|
||||
WriteFile(file, "1\n", 2, &nBytes, nullptr);
|
||||
}
|
||||
|
||||
if (sUser32BeforeBlocklist) {
|
||||
WriteFile(file, kUser32BeforeBlocklistParameter,
|
||||
kUser32BeforeBlocklistParameterLen, &nBytes, nullptr);
|
||||
WriteFile(file, "1\n", 2, &nBytes, nullptr);
|
||||
}
|
||||
}
|
||||
#endif
|
38
mozglue/build/WindowsDllBlocklist.h
Normal file
38
mozglue/build/WindowsDllBlocklist.h
Normal 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
|
@ -31,6 +31,11 @@ if CONFIG['OS_TARGET'] == 'Android':
|
||||
'BionicGlue.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
SOURCES += [
|
||||
'WindowsDllBlocklist.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_NUWA_PROCESS']:
|
||||
EXPORTS.ipc += [
|
||||
'Nuwa.h',
|
||||
@ -42,6 +47,7 @@ if CONFIG['MOZ_NUWA_PROCESS']:
|
||||
EXPORTS.mozilla += [
|
||||
'arm.h',
|
||||
'SSE.h',
|
||||
'WindowsDllBlocklist.h',
|
||||
]
|
||||
|
||||
if CONFIG['CPU_ARCH'].startswith('x86'):
|
||||
|
@ -83,6 +83,7 @@ using mozilla::InjectCrashRunnable;
|
||||
|
||||
#include "mozilla/mozalloc_oom.h"
|
||||
#include "mozilla/LateWriteChecks.h"
|
||||
#include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter");
|
||||
@ -222,11 +223,6 @@ static const char kIsGarbageCollectingParameter[] = "IsGarbageCollecting=";
|
||||
static const int kIsGarbageCollectingParameterLen =
|
||||
sizeof(kIsGarbageCollectingParameter)-1;
|
||||
|
||||
#ifdef XP_WIN
|
||||
static const char kBlockedDllsParameter[] = "BlockedDllList=";
|
||||
static const int kBlockedDllsParameterLen = sizeof(kBlockedDllsParameter) - 1;
|
||||
#endif
|
||||
|
||||
// this holds additional data sent via the API
|
||||
static Mutex* crashReporterAPILock;
|
||||
static Mutex* notesFieldLock;
|
||||
@ -545,9 +541,10 @@ bool MinidumpCallback(
|
||||
WriteFile(hFile, isGarbageCollecting ? "1" : "0", 1, &nBytes, nullptr);
|
||||
WriteFile(hFile, "\n", 1, &nBytes, nullptr);
|
||||
}
|
||||
WriteFile(hFile, kBlockedDllsParameter, kBlockedDllsParameterLen, &nBytes, nullptr);
|
||||
WriteBlockedDlls(hFile);
|
||||
WriteFile(hFile, "\n", 1, &nBytes, nullptr);
|
||||
|
||||
#ifdef HAS_DLL_BLOCKLIST
|
||||
DllBlocklist_WriteNotes(hFile);
|
||||
#endif
|
||||
|
||||
// Try to get some information about memory.
|
||||
MEMORYSTATUSEX statex;
|
||||
|
@ -44,11 +44,6 @@ nsresult AppendAppNotesToCrashReport(const nsACString& data);
|
||||
|
||||
nsresult SetGarbageCollecting(bool collecting);
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Implemented by the blocklist, this method writes the blocklist annotation
|
||||
void WriteBlockedDlls(HANDLE file);
|
||||
#endif
|
||||
|
||||
nsresult SetRestartArgs(int argc, char** argv);
|
||||
nsresult SetupExtraData(nsIFile* aAppDataDirectory,
|
||||
const nsACString& aBuildID);
|
||||
|
@ -11,6 +11,7 @@ EXTRA_DSO_LDOPTS += \
|
||||
$(MOZ_GNOMEVFS_LIBS) \
|
||||
$(GLIB_LIBS) \
|
||||
$(MOZ_GIO_LIBS) \
|
||||
$(MOZ_DBUS_GLIB_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/components/build/
|
||||
@ -22,6 +23,7 @@ CXXFLAGS += \
|
||||
$(MOZ_GNOMEVFS_CFLAGS) \
|
||||
$(MOZ_GIO_CFLAGS) \
|
||||
$(GLIB_CFLAGS) \
|
||||
$(MOZ_DBUS_GLIB_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_ENABLE_GTK
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <dbus/dbus-glib.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
|
||||
char *
|
||||
@ -377,6 +379,56 @@ nsGIOService::ShowURIForInput(const nsACString& aUri)
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGIOService::OrgFreedesktopFileManager1ShowItems(const nsACString& aPath)
|
||||
{
|
||||
GError* error = nullptr;
|
||||
static bool org_freedesktop_FileManager1_exists = true;
|
||||
|
||||
if (!org_freedesktop_FileManager1_exists) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
DBusGConnection* dbusGConnection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
|
||||
|
||||
if (!dbusGConnection) {
|
||||
if (error) {
|
||||
g_printerr("Failed to open connection to session bus: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
char *uri = g_filename_to_uri(PromiseFlatCString(aPath).get(), nullptr, nullptr);
|
||||
if (uri == NULL) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
DBusConnection* dbusConnection = dbus_g_connection_get_connection(dbusGConnection);
|
||||
// Make sure we do not exit the entire program if DBus connection get lost.
|
||||
dbus_connection_set_exit_on_disconnect(dbusConnection, false);
|
||||
|
||||
DBusGProxy* dbusGProxy = dbus_g_proxy_new_for_name(dbusGConnection,
|
||||
"org.freedesktop.FileManager1",
|
||||
"/org/freedesktop/FileManager1",
|
||||
"org.freedesktop.FileManager1");
|
||||
|
||||
const char *uris[2] = { uri, nullptr };
|
||||
gboolean rv_dbus_call = dbus_g_proxy_call (dbusGProxy, "ShowItems", nullptr, G_TYPE_STRV, uris,
|
||||
G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID);
|
||||
|
||||
g_object_unref(dbusGProxy);
|
||||
dbus_g_connection_unref(dbusGConnection);
|
||||
g_free(uri);
|
||||
|
||||
if (!rv_dbus_call) {
|
||||
org_freedesktop_FileManager1_exists = false;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or find already existing application info for specified command
|
||||
* and application name.
|
||||
|
@ -24,7 +24,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
EXPORTS += ['nsWindowsDllInterceptor.h']
|
||||
SOURCES += [
|
||||
'nsNativeAppSupportWin.cpp',
|
||||
'nsWindowsDllBlocklist.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
EXPORTS += ['MacQuirks.h']
|
||||
|
@ -11,24 +11,10 @@
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <fstream>
|
||||
#include "platform.h"
|
||||
#include "shared-libraries.h"
|
||||
|
||||
#if !defined(__GLIBC__) && ANDROID_VERSION < 18
|
||||
/* a crapy version of getline, because it's not included in old bionics */
|
||||
static ssize_t getline(char **lineptr, size_t *n, FILE *stream)
|
||||
{
|
||||
char *ret;
|
||||
if (!*lineptr) {
|
||||
*lineptr = (char*)malloc(4096);
|
||||
}
|
||||
ret = fgets(*lineptr, 4096, stream);
|
||||
if (!ret)
|
||||
return 0;
|
||||
return strlen(*lineptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(MOZ_WIDGET_GONK)
|
||||
// TODO fix me with proper include
|
||||
#include "nsDebug.h"
|
||||
@ -91,11 +77,10 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
|
||||
pid_t pid = getpid();
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, PATH_MAX, "/proc/%d/maps", pid);
|
||||
FILE *maps = fopen(path, "r");
|
||||
char *line = NULL;
|
||||
std::ifstream maps(path);
|
||||
std::string line;
|
||||
int count = 0;
|
||||
size_t line_size = 0;
|
||||
while (maps && getline (&line, &line_size, maps) > 0) {
|
||||
while (std::getline(maps, line)) {
|
||||
int ret;
|
||||
//XXX: needs input sanitizing
|
||||
unsigned long start;
|
||||
@ -103,7 +88,7 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
|
||||
char perm[6] = "";
|
||||
unsigned long offset;
|
||||
char name[PATH_MAX] = "";
|
||||
ret = sscanf(line,
|
||||
ret = sscanf(line.c_str(),
|
||||
"%lx-%lx %6s %lx %*s %*x %" PATH_MAX_STRING(PATH_MAX) "s\n",
|
||||
&start, &end, perm, &offset, name);
|
||||
if (!strchr(perm, 'x')) {
|
||||
@ -128,6 +113,5 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
|
||||
}
|
||||
count++;
|
||||
}
|
||||
free(line);
|
||||
return info;
|
||||
}
|
||||
|
@ -518,8 +518,10 @@ CycleCollectedJSRuntime::DescribeGCThing(bool aIsMarked, void* aThing,
|
||||
}
|
||||
|
||||
char name[72];
|
||||
uint64_t compartmentAddress = 0;
|
||||
if (aTraceKind == JSTRACE_OBJECT) {
|
||||
JSObject* obj = static_cast<JSObject*>(aThing);
|
||||
compartmentAddress = (uint64_t)js::GetObjectCompartment(obj);
|
||||
const js::Class* clasp = js::GetObjectClass(obj);
|
||||
|
||||
// Give the subclass a chance to do something
|
||||
@ -555,7 +557,7 @@ CycleCollectedJSRuntime::DescribeGCThing(bool aIsMarked, void* aThing,
|
||||
}
|
||||
|
||||
// Disable printing global for objects while we figure out ObjShrink fallout.
|
||||
aCb.DescribeGCedNode(aIsMarked, name);
|
||||
aCb.DescribeGCedNode(aIsMarked, name, compartmentAddress);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1115,7 +1115,7 @@ GraphWalker<Visitor>::DoWalk(nsDeque &aQueue)
|
||||
struct CCGraphDescriber : public LinkedListElement<CCGraphDescriber>
|
||||
{
|
||||
CCGraphDescriber()
|
||||
: mAddress("0x"), mToAddress("0x"), mCnt(0), mType(eUnknown) {}
|
||||
: mAddress("0x"), mCnt(0), mType(eUnknown) {}
|
||||
|
||||
enum Type
|
||||
{
|
||||
@ -1129,8 +1129,8 @@ struct CCGraphDescriber : public LinkedListElement<CCGraphDescriber>
|
||||
};
|
||||
|
||||
nsCString mAddress;
|
||||
nsCString mToAddress;
|
||||
nsCString mName;
|
||||
nsCString mCompartmentOrToAddress;
|
||||
uint32_t mCnt;
|
||||
Type mType;
|
||||
};
|
||||
@ -1290,7 +1290,8 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD NoteGCedObject(uint64_t aAddress, bool aMarked,
|
||||
const char *aObjectDescription)
|
||||
const char *aObjectDescription,
|
||||
uint64_t aCompartmentAddress)
|
||||
{
|
||||
if (!mDisableLog) {
|
||||
fprintf(mStream, "%p [gc%s] %s\n", (void*)aAddress,
|
||||
@ -1305,6 +1306,12 @@ public:
|
||||
CCGraphDescriber::eGCedObject;
|
||||
d->mAddress = mCurrentAddress;
|
||||
d->mName.Append(aObjectDescription);
|
||||
if (aCompartmentAddress) {
|
||||
d->mCompartmentOrToAddress.AssignLiteral("0x");
|
||||
d->mCompartmentOrToAddress.AppendInt(aCompartmentAddress, 16);
|
||||
} else {
|
||||
d->mCompartmentOrToAddress.SetIsVoid(true);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1318,7 +1325,8 @@ public:
|
||||
mDescribers.insertBack(d);
|
||||
d->mType = CCGraphDescriber::eEdge;
|
||||
d->mAddress = mCurrentAddress;
|
||||
d->mToAddress.AppendInt(aToAddress, 16);
|
||||
d->mCompartmentOrToAddress.AssignLiteral("0x");
|
||||
d->mCompartmentOrToAddress.AppendInt(aToAddress, 16);
|
||||
d->mName.Append(aEdgeName);
|
||||
}
|
||||
return NS_OK;
|
||||
@ -1421,11 +1429,12 @@ public:
|
||||
aHandler->NoteGCedObject(d->mAddress,
|
||||
d->mType ==
|
||||
CCGraphDescriber::eGCMarkedObject,
|
||||
d->mName);
|
||||
d->mName,
|
||||
d->mCompartmentOrToAddress);
|
||||
break;
|
||||
case CCGraphDescriber::eEdge:
|
||||
aHandler->NoteEdge(d->mAddress,
|
||||
d->mToAddress,
|
||||
d->mCompartmentOrToAddress,
|
||||
d->mName);
|
||||
break;
|
||||
case CCGraphDescriber::eRoot:
|
||||
@ -1598,7 +1607,8 @@ public:
|
||||
// nsCycleCollectionTraversalCallback methods.
|
||||
NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refCount,
|
||||
const char *objName);
|
||||
NS_IMETHOD_(void) DescribeGCedNode(bool isMarked, const char *objName);
|
||||
NS_IMETHOD_(void) DescribeGCedNode(bool isMarked, const char *objName,
|
||||
uint64_t aCompartmentAddress);
|
||||
|
||||
NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child);
|
||||
NS_IMETHOD_(void) NoteJSChild(void *child);
|
||||
@ -1782,14 +1792,15 @@ GCGraphBuilder::DescribeRefCountedNode(nsrefcnt refCount, const char *objName)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
GCGraphBuilder::DescribeGCedNode(bool isMarked, const char *objName)
|
||||
GCGraphBuilder::DescribeGCedNode(bool isMarked, const char *objName,
|
||||
uint64_t aCompartmentAddress)
|
||||
{
|
||||
uint32_t refCount = isMarked ? UINT32_MAX : 0;
|
||||
mCollector->mVisitedGCed++;
|
||||
|
||||
if (mListener) {
|
||||
mListener->NoteGCedObject((uint64_t)mCurrPi->mPointer, isMarked,
|
||||
objName);
|
||||
objName, aCompartmentAddress);
|
||||
}
|
||||
|
||||
DescribeNode(refCount, objName);
|
||||
@ -1923,7 +1934,8 @@ public:
|
||||
NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refcount,
|
||||
const char *objname) {}
|
||||
NS_IMETHOD_(void) DescribeGCedNode(bool ismarked,
|
||||
const char *objname) {}
|
||||
const char *objname,
|
||||
uint64_t aCompartmentAddress) {}
|
||||
NS_IMETHOD_(void) NoteNextEdgeName(const char* name) {}
|
||||
bool MayHaveChild() {
|
||||
return mMayHaveChild;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user