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