зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
6efee7d862
|
@ -38,6 +38,7 @@
|
|||
#include "nsTableOuterFrame.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -869,15 +870,10 @@ HTMLTableAccessible::Description(nsString& aDescription)
|
|||
bool
|
||||
HTMLTableAccessible::HasDescendant(const nsAString& aTagName, bool aAllowEmpty)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> tableElt(do_QueryInterface(mContent));
|
||||
NS_ENSURE_TRUE(tableElt, false);
|
||||
nsCOMPtr<nsIHTMLCollection> elements =
|
||||
mContent->AsElement()->GetElementsByTagName(aTagName);
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLCollection> nodeList;
|
||||
tableElt->GetElementsByTagName(aTagName, getter_AddRefs(nodeList));
|
||||
NS_ENSURE_TRUE(nodeList, false);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> foundItem;
|
||||
nodeList->Item(0, getter_AddRefs(foundItem));
|
||||
Element* foundItem = elements->Item(0);
|
||||
if (!foundItem)
|
||||
return false;
|
||||
|
||||
|
@ -886,11 +882,10 @@ HTMLTableAccessible::HasDescendant(const nsAString& aTagName, bool aAllowEmpty)
|
|||
|
||||
// Make sure that the item we found has contents and either has multiple
|
||||
// children or the found item is not a whitespace-only text node.
|
||||
nsCOMPtr<nsIContent> foundItemContent = do_QueryInterface(foundItem);
|
||||
if (foundItemContent->GetChildCount() > 1)
|
||||
if (foundItem->GetChildCount() > 1)
|
||||
return true; // Treat multiple child nodes as non-empty
|
||||
|
||||
nsIContent *innerItemContent = foundItemContent->GetFirstChild();
|
||||
nsIContent *innerItemContent = foundItem->GetFirstChild();
|
||||
if (innerItemContent && !innerItemContent->TextIsOnlyWhitespace())
|
||||
return true;
|
||||
|
||||
|
@ -901,8 +896,7 @@ HTMLTableAccessible::HasDescendant(const nsAString& aTagName, bool aAllowEmpty)
|
|||
// caption element only. On another hand we create accessible object for
|
||||
// the first entry of caption element (see
|
||||
// HTMLTableAccessible::CacheChildren).
|
||||
nodeList->Item(1, getter_AddRefs(foundItem));
|
||||
return !!foundItem;
|
||||
return !!elements->Item(1);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -112,6 +112,11 @@ var tests = {
|
|||
iconURL: "chrome://browser/skin/Info.png",
|
||||
counter: 1
|
||||
};
|
||||
|
||||
// Disable the transition
|
||||
let panel = document.getElementById("social-notification-panel");
|
||||
panel.setAttribute("animate", "false");
|
||||
|
||||
// click on panel to open and wait for visibility
|
||||
let provider = Social._getProviderFromOrigin(manifest2.origin);
|
||||
let id = SocialStatus._toolbarHelper.idFromOrigin(manifest2.origin);
|
||||
|
@ -131,8 +136,8 @@ var tests = {
|
|||
case "got-social-panel-visibility":
|
||||
ok(true, "got the panel message " + e.data.result);
|
||||
if (e.data.result == "shown") {
|
||||
let panel = document.getElementById("social-notification-panel");
|
||||
panel.hidePopup();
|
||||
panel.removeAttribute("animate");
|
||||
} else {
|
||||
port.postMessage({topic: "test-ambient-notification", data: icon});
|
||||
port.close();
|
||||
|
|
|
@ -63,11 +63,14 @@ function checkProviderPrefsEmpty(isError) {
|
|||
}
|
||||
|
||||
function defaultFinishChecks() {
|
||||
PopupNotifications.transitionsEnabled = true;
|
||||
checkProviderPrefsEmpty(true);
|
||||
finish();
|
||||
}
|
||||
|
||||
function runSocialTestWithProvider(manifest, callback, finishcallback) {
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
|
||||
let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
|
||||
|
||||
let manifests = Array.isArray(manifest) ? manifest : [manifest];
|
||||
|
@ -158,6 +161,8 @@ function runSocialTests(tests, cbPreTest, cbPostTest, cbFinish) {
|
|||
let providersAtStart = Social.providers.length;
|
||||
info("runSocialTests: start test run with " + providersAtStart + " providers");
|
||||
|
||||
PopupNotifications.transitionsEnabled = false;
|
||||
|
||||
if (cbPreTest === undefined) {
|
||||
cbPreTest = function(cb) {cb()};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
type="arrow"
|
||||
hidden="true"
|
||||
flip="slide"
|
||||
animate="false"
|
||||
position="bottomcenter topright"
|
||||
noautofocus="true">
|
||||
<panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView">
|
||||
|
|
|
@ -54,6 +54,7 @@ _MOZBUILD_EXTERNAL_VARIABLES := \
|
|||
JAR_MANIFEST \
|
||||
JAVA_JAR_TARGETS \
|
||||
JS_MODULES_PATH \
|
||||
LD_VERSION_SCRIPT \
|
||||
LIBRARY_NAME \
|
||||
MODULE \
|
||||
MSVC_ENABLE_PGO \
|
||||
|
|
|
@ -510,6 +510,10 @@ ifeq ($(OS_ARCH),Linux)
|
|||
ifdef IS_COMPONENT
|
||||
EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic
|
||||
endif
|
||||
ifdef LD_VERSION_SCRIPT
|
||||
EXTRA_DSO_LDOPTS += -Wl,--version-script,$(LD_VERSION_SCRIPT)
|
||||
EXTRA_DEPS += $(LD_VERSION_SCRIPT)
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
|
@ -1020,6 +1024,10 @@ $(filter %.s,$(CPPSRCS:%.cc=%.s)): %.s: %.cc $(call mkdir_deps,$(MDDEPDIR))
|
|||
$(REPORT_BUILD)
|
||||
$(CCC) -S $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
|
||||
|
||||
$(filter %.s,$(CPPSRCS:%.cxx=%.s)): %.s: %.cpp $(call mkdir_deps,$(MDDEPDIR))
|
||||
$(REPORT_BUILD)
|
||||
$(CCC) -S $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
|
||||
|
||||
$(filter %.s,$(CSRCS:%.c=%.s)): %.s: %.c $(call mkdir_deps,$(MDDEPDIR))
|
||||
$(REPORT_BUILD)
|
||||
$(CC) -S $(COMPILE_CFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
|
||||
|
@ -1035,6 +1043,7 @@ ifneq (,$(filter %.i,$(MAKECMDGOALS)))
|
|||
_group_srcs = $(sort $(patsubst %.$1,%.i,$(filter %.$1,$2 $(notdir $2))))
|
||||
_PREPROCESSED_CPP_FILES := $(call _group_srcs,cpp,$(CPPSRCS))
|
||||
_PREPROCESSED_CC_FILES := $(call _group_srcs,cc,$(CPPSRCS))
|
||||
_PREPROCESSED_CXX_FILES := $(call _group_srcs,cxx,$(CPPSRCS))
|
||||
_PREPROCESSED_C_FILES := $(call _group_srcs,c,$(CSRCS))
|
||||
_PREPROCESSED_CMM_FILES := $(call _group_srcs,mm,$(CMMSRCS))
|
||||
|
||||
|
@ -1044,7 +1053,7 @@ VPATH += $(addprefix $(srcdir)/,$(sort $(dir $(CPPSRCS) $(CSRCS) $(CMMSRCS))))
|
|||
|
||||
# Make preprocessed files PHONY so they are always executed, since they are
|
||||
# manual targets and we don't necessarily write to $@.
|
||||
.PHONY: $(_PREPROCESSED_CPP_FILES) $(_PREPROCESSED_CC_FILES) $(_PREPROCESSED_C_FILES) $(_PREPROCESSED_CMM_FILES)
|
||||
.PHONY: $(_PREPROCESSED_CPP_FILES) $(_PREPROCESSED_CC_FILES) $(_PREPROCESSED_CXX_FILES) $(_PREPROCESSED_C_FILES) $(_PREPROCESSED_CMM_FILES)
|
||||
|
||||
$(_PREPROCESSED_CPP_FILES): %.i: %.cpp $(call mkdir_deps,$(MDDEPDIR))
|
||||
$(REPORT_BUILD)
|
||||
|
@ -1056,6 +1065,11 @@ $(_PREPROCESSED_CC_FILES): %.i: %.cc $(call mkdir_deps,$(MDDEPDIR))
|
|||
$(addprefix $(MKDIR) -p ,$(filter-out .,$(@D)))
|
||||
$(CCC) -C $(PREPROCESS_OPTION)$@ $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
|
||||
|
||||
$(_PREPROCESSED_CXX_FILES): %.i: %.cxx $(call mkdir_deps,$(MDDEPDIR))
|
||||
$(REPORT_BUILD)
|
||||
$(addprefix $(MKDIR) -p ,$(filter-out .,$(@D)))
|
||||
$(CCC) -C $(PREPROCESS_OPTION)$@ $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
|
||||
|
||||
$(_PREPROCESSED_C_FILES): %.i: %.c $(call mkdir_deps,$(MDDEPDIR))
|
||||
$(REPORT_BUILD)
|
||||
$(addprefix $(MKDIR) -p ,$(filter-out .,$(@D)))
|
||||
|
@ -1074,7 +1088,7 @@ PP_UNIFIED ?= 1
|
|||
# infinite loop if the filename doesn't exist in the unified source files.
|
||||
ifndef PP_REINVOKE
|
||||
|
||||
MATCH_cpp = \(cpp\|cc\)
|
||||
MATCH_cpp = \(cpp\|cc|cxx\)
|
||||
UPPER_c = C
|
||||
UPPER_cpp = CPP
|
||||
UPPER_mm = CMM
|
||||
|
|
|
@ -2928,7 +2928,7 @@ dnl Checks for library functions.
|
|||
dnl ========================================================
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_FUNC_MEMCMP
|
||||
AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize localtime_r)
|
||||
AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize localtime_r arc4random arc4random_buf)
|
||||
|
||||
dnl check for clock_gettime(), the CLOCK_MONOTONIC clock
|
||||
AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC),
|
||||
|
@ -3589,7 +3589,7 @@ MOZ_ARG_WITH_BOOL(system-nss,
|
|||
_USE_SYSTEM_NSS=1 )
|
||||
|
||||
if test -n "$_USE_SYSTEM_NSS"; then
|
||||
AM_PATH_NSS(3.16, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
|
||||
AM_PATH_NSS(3.16.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_NATIVE_NSS"; then
|
||||
|
@ -8803,6 +8803,7 @@ AC_SUBST(CPU_ARCH)
|
|||
AC_SUBST(INTEL_ARCHITECTURE)
|
||||
AC_SUBST(HAVE_TOOLCHAIN_SUPPORT_MSSSE3)
|
||||
AC_SUBST(HAVE_TOOLCHAIN_SUPPORT_MSSE4_1)
|
||||
AC_SUBST(GCC_USE_GNU_LD)
|
||||
|
||||
AC_SUBST(MOZ_CHROME_FILE_FORMAT)
|
||||
|
||||
|
|
|
@ -1350,6 +1350,8 @@ private:
|
|||
// Set if the element has a parser insertion mode other than "in body",
|
||||
// per the HTML5 "Parse state" section.
|
||||
ElementHasWeirdParserInsertionMode,
|
||||
// Parser sets this flag if it has notified about the node.
|
||||
ParserHasNotified,
|
||||
// Guard value
|
||||
BooleanFlagCount
|
||||
};
|
||||
|
@ -1490,6 +1492,8 @@ public:
|
|||
bool IsScopedStyleRoot() { return GetBoolFlag(ElementIsScopedStyleRoot); }
|
||||
bool HasRelevantHoverRules() const { return GetBoolFlag(NodeHasRelevantHoverRules); }
|
||||
void SetHasRelevantHoverRules() { SetBoolFlag(NodeHasRelevantHoverRules); }
|
||||
void SetParserHasNotified() { SetBoolFlag(ParserHasNotified); };
|
||||
bool HasParserNotified() { return GetBoolFlag(ParserHasNotified); }
|
||||
protected:
|
||||
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
|
||||
void SetInDocument() { SetBoolFlag(IsInDocument); }
|
||||
|
|
|
@ -559,7 +559,7 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
|||
}
|
||||
|
||||
nsRefPtr<WebSocket> webSocket = new WebSocket(ownerWindow);
|
||||
nsresult rv = webSocket->Init(aGlobal.GetContext(), principal,
|
||||
nsresult rv = webSocket->Init(aGlobal.Context(), principal,
|
||||
aUrl, protocolArray);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
|
|
|
@ -52,8 +52,8 @@ ImageData::Constructor(const GlobalObject& aGlobal,
|
|||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
js::AssertSameCompartment(aGlobal.GetContext(), aGlobal.Get());
|
||||
JSObject* data = Uint8ClampedArray::Create(aGlobal.GetContext(),
|
||||
js::AssertSameCompartment(aGlobal.Context(), aGlobal.Get());
|
||||
JSObject* data = Uint8ClampedArray::Create(aGlobal.Context(),
|
||||
length.value());
|
||||
if (!data) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
|
|
|
@ -13,14 +13,16 @@
|
|||
#include "nsDOMSettableTokenList.h"
|
||||
#include "nsFormSubmission.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Output)
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Output)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
HTMLOutputElement::HTMLOutputElement(already_AddRefed<nsINodeInfo>& aNodeInfo)
|
||||
HTMLOutputElement::HTMLOutputElement(already_AddRefed<nsINodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser)
|
||||
: nsGenericHTMLFormElement(aNodeInfo)
|
||||
, mValueModeFlag(eModeDefault)
|
||||
, mIsDoneAddingChildren(!aFromParser)
|
||||
{
|
||||
AddMutationObserver(this);
|
||||
|
||||
|
@ -93,6 +95,12 @@ HTMLOutputElement::ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
|
|||
aValue, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLOutputElement::DoneAddingChildren(bool aHaveNotified)
|
||||
{
|
||||
mIsDoneAddingChildren = true;
|
||||
}
|
||||
|
||||
EventStates
|
||||
HTMLOutputElement::IntrinsicState() const
|
||||
{
|
||||
|
@ -170,7 +178,7 @@ HTMLOutputElement::HtmlFor()
|
|||
|
||||
void HTMLOutputElement::DescendantsChanged()
|
||||
{
|
||||
if (mValueModeFlag == eModeDefault) {
|
||||
if (mIsDoneAddingChildren && mValueModeFlag == eModeDefault) {
|
||||
if (!nsContentUtils::GetNodeTextContent(this, true, mDefaultValue)) {
|
||||
NS_RUNTIMEABORT("OOM");
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ class HTMLOutputElement MOZ_FINAL : public nsGenericHTMLFormElement,
|
|||
public:
|
||||
using nsIConstraintValidation::GetValidationMessage;
|
||||
|
||||
HTMLOutputElement(already_AddRefed<nsINodeInfo>& aNodeInfo);
|
||||
HTMLOutputElement(already_AddRefed<nsINodeInfo>& aNodeInfo,
|
||||
FromParser aFromParser = NOT_FROM_PARSER);
|
||||
virtual ~HTMLOutputElement();
|
||||
|
||||
// nsISupports
|
||||
|
@ -39,6 +40,8 @@ public:
|
|||
bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
|
||||
const nsAString& aValue, nsAttrValue& aResult) MOZ_OVERRIDE;
|
||||
|
||||
virtual void DoneAddingChildren(bool aHaveNotified) MOZ_OVERRIDE;
|
||||
|
||||
EventStates IntrinsicState() const MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
|
@ -101,6 +104,7 @@ protected:
|
|||
};
|
||||
|
||||
ValueModeFlag mValueModeFlag;
|
||||
bool mIsDoneAddingChildren;
|
||||
nsString mDefaultValue;
|
||||
nsRefPtr<nsDOMSettableTokenList> mTokenList;
|
||||
};
|
||||
|
|
|
@ -1966,6 +1966,25 @@ void MediaDecoderStateMachine::DecodeSeek()
|
|||
video = mReader->FindStartTime(nextSampleStartTime);
|
||||
}
|
||||
|
||||
if (seekTime > mediaTime &&
|
||||
nextSampleStartTime < mediaTime &&
|
||||
mSeekTarget.mType == SeekTarget::PrevSyncPoint) {
|
||||
// We are doing a fastSeek, but we ended up *before* the previous
|
||||
// playback position. This is surprising UX, so switch to an accurate
|
||||
// seek and decode to the seek target. This is not conformant to the
|
||||
// spec, fastSeek should always be fast, but until we get the time to
|
||||
// change all Readers to seek to the keyframe after the currentTime
|
||||
// in this case, we'll just decode forward. Bug 1026330.
|
||||
ResetPlayback();
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
res = mReader->DecodeToTarget(seekTime);
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
video = mReader->FindStartTime(nextSampleStartTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup timestamp state.
|
||||
if (seekTime == mEndTime) {
|
||||
newCurrentTime = mAudioStartTime = seekTime;
|
||||
|
|
|
@ -86,9 +86,9 @@ MediaKeyMessageEvent::Constructor(const GlobalObject& aGlobal,
|
|||
if (aEventInitDict.mMessage.WasPassed()) {
|
||||
const auto& a = aEventInitDict.mMessage.Value();
|
||||
a.ComputeLengthAndData();
|
||||
e->mMessage = Uint8Array::Create(aGlobal.GetContext(), owner, a.Length(), a.Data());
|
||||
e->mMessage = Uint8Array::Create(aGlobal.Context(), owner, a.Length(), a.Data());
|
||||
} else {
|
||||
e->mMessage = Uint8Array::Create(aGlobal.GetContext(), owner, 0, nullptr);
|
||||
e->mMessage = Uint8Array::Create(aGlobal.Context(), owner, 0, nullptr);
|
||||
}
|
||||
if (!e->mMessage) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
|
|
|
@ -78,7 +78,7 @@ MediaKeyNeededEvent::Constructor(const GlobalObject& aGlobal,
|
|||
!aEventInitDict.mInitData.Value().IsNull()) {
|
||||
const auto& a = aEventInitDict.mInitData.Value().Value();
|
||||
a.ComputeLengthAndData();
|
||||
e->mInitData = Uint8Array::Create(aGlobal.GetContext(), owner, a.Length(), a.Data());
|
||||
e->mInitData = Uint8Array::Create(aGlobal.Context(), owner, a.Length(), a.Data());
|
||||
if (!e->mInitData) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<!-- This video file has a timescale of 0 in the mdhd atom -->
|
||||
<video src="0-timescale.mp4"
|
||||
onerror="document.documentElement.className=undefined"
|
||||
onloadedmetadata="document.documentElement.className=undefined">
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
Двоичный файл не отображается.
|
@ -1,3 +1,4 @@
|
|||
skip-if(B2G) load 0-timescale.html
|
||||
skip-if(B2G) load 459439-1.html # bug 888557
|
||||
load 466607-1.html
|
||||
load 466945-1.html
|
||||
|
|
|
@ -347,6 +347,7 @@ skip-if = buildapp == 'b2g' # bug 1021676
|
|||
[test_error_in_video_document.html]
|
||||
[test_error_on_404.html]
|
||||
[test_fastSeek.html]
|
||||
[test_fastSeek-forwards.html]
|
||||
[test_info_leak.html]
|
||||
[test_invalid_reject.html]
|
||||
[test_load.html]
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1022913
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1022913</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<script type="application/javascript">
|
||||
|
||||
// Test that if we're doing a fastSeek() forwards that we don't end up
|
||||
// seeking backwards. This can happen if the keyframe before the seek
|
||||
// target is before the current playback position. We'd prefer to seek to
|
||||
// the keyframe after the seek target in this case, but we don't implement
|
||||
// this yet (bug 1026330).
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
var onSecondSeekComplete = function(event) {
|
||||
var v = event.target;
|
||||
ok(v.currentTime >= v.firstSeekTarget, v.name + " seek never go backwards. time=" + v.currentTime + " firstSeekTarget=" + v.firstSeekTarget + " secondSeekTarget=" + v.secondSeekTarget);
|
||||
manager.finished(v.token);
|
||||
};
|
||||
|
||||
var onFirstSeekComplete = function(event) {
|
||||
var v = event.target;
|
||||
v.removeEventListener("seeked", onFirstSeekComplete);
|
||||
// Seek to 75% of the way between the start and the first keyframe
|
||||
// using fastSeek. We then test that the currentTime doesn't drop back
|
||||
// to the previous keyframe, currentTime should go forwards.
|
||||
v.addEventListener("seeked", onSecondSeekComplete);
|
||||
v.secondSeekTarget = v.keyframes[1] * 0.75;
|
||||
v.fastSeek(v.secondSeekTarget);
|
||||
}
|
||||
|
||||
var onLoadedMetadata = function(event) {
|
||||
// Seek to the mid-point between the start and the first keyframe.
|
||||
var v = event.target;
|
||||
v.addEventListener("seeked", onFirstSeekComplete);
|
||||
v.firstSeekTarget = v.keyframes[1] * 0.5;
|
||||
v.currentTime = v.firstSeekTarget;
|
||||
}
|
||||
|
||||
function startTest(test, token) {
|
||||
manager.started(token);
|
||||
v = document.createElement("video");
|
||||
v.src = test.name;
|
||||
v.name = test.name;
|
||||
v.preload = "metadata";
|
||||
v.token = token;
|
||||
v.target = 0;
|
||||
v.keyframes = test.keyframes;
|
||||
v.keyframeIndex = 0;
|
||||
ok(v.keyframes.length >= 2, v.name + " - video should have at least two sync points");
|
||||
v.addEventListener("loadedmetadata", onLoadedMetadata);
|
||||
document.body.appendChild(v);
|
||||
}
|
||||
|
||||
manager.runTests(gFastSeekTests, startTest);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1022913">Mozilla Bug 1022913</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
LIB_IS_C_ONLY = 1
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
DEFFILE = $(CURDIR)/sqlite-processed.def
|
||||
|
||||
|
@ -20,10 +22,25 @@ sqlite-version.h: sqlite-version.py sqlite3.h
|
|||
# We have to preprocess our def file because we need different symbols in debug
|
||||
# builds exposed that are not built in non-debug builds.
|
||||
$(DEFFILE): sqlite.def
|
||||
@$(call py_action,preprocessor,$(DEFINES) \
|
||||
@$(call py_action,preprocessor,$(DEFINES) $(XULPPFLAGS) \
|
||||
$(srcdir)/sqlite.def -o $(DEFFILE))
|
||||
|
||||
export:: sqlite-version.h
|
||||
else
|
||||
ifndef MOZ_FOLD_LIBS
|
||||
ifdef GCC_USE_GNU_LD
|
||||
|
||||
GARBAGE += \
|
||||
$(LD_VERSION_SCRIPT) \
|
||||
$(NULL)
|
||||
|
||||
# Convert to the format we need for ld.
|
||||
$(LD_VERSION_SCRIPT): $(srcdir)/sqlite.def
|
||||
@$(call py_action,convert_def_file, \
|
||||
$(DEFINES) $(ACDEFINES) $(XULPPFLAGS) -o $@ $^)
|
||||
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (Darwin,$(OS_TARGET))
|
||||
|
|
|
@ -74,6 +74,11 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||
RCFILE = 'sqlite.rc'
|
||||
RESFILE = 'sqlite.res'
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'Linux' and \
|
||||
not CONFIG['MOZ_FOLD_LIBS'] and \
|
||||
CONFIG['GCC_USE_GNU_LD']:
|
||||
LD_VERSION_SCRIPT = 'sqlite-processed.def'
|
||||
|
||||
# Suppress warnings in third-party code.
|
||||
if CONFIG['GNU_CC']:
|
||||
CFLAGS += [
|
||||
|
|
|
@ -126,6 +126,9 @@ EXPORTS
|
|||
sqlite3_step
|
||||
sqlite3_stmt_readonly
|
||||
sqlite3_stmt_status
|
||||
#ifdef XP_UNIX
|
||||
sqlite3_temp_directory
|
||||
#endif
|
||||
sqlite3_thread_cleanup
|
||||
sqlite3_total_changes
|
||||
sqlite3_trace
|
||||
|
@ -151,7 +154,7 @@ EXPORTS
|
|||
sqlite3_vfs_unregister
|
||||
sqlite3_vfs_register
|
||||
sqlite3_vmprintf
|
||||
#ifdef SQLITE_DEBUG
|
||||
#ifdef DEBUG
|
||||
sqlite3_mutex_held
|
||||
sqlite3_mutex_notheld
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,6 @@ public:
|
|||
|
||||
static already_AddRefed<Activity>
|
||||
Constructor(const GlobalObject& aOwner,
|
||||
JSContext* aCx,
|
||||
const ActivityOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
|
@ -36,7 +35,7 @@ public:
|
|||
}
|
||||
|
||||
nsRefPtr<Activity> activity = new Activity(window);
|
||||
aRv = activity->Initialize(window, aCx, aOptions);
|
||||
aRv = activity->Initialize(window, aOwner.Context(), aOptions);
|
||||
return activity.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -910,7 +910,7 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
|
|||
|
||||
ErrorResult rv;
|
||||
nsRefPtr<nsPerformance> performance = win->GetPerformance(rv);
|
||||
if (rv.Failed()) {
|
||||
if (rv.Failed() || !performance) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
// The context that this returns is not guaranteed to be in the compartment of
|
||||
// the object returned from Get(), in fact it's generally in the caller's
|
||||
// compartment.
|
||||
JSContext* GetContext() const
|
||||
JSContext* Context() const
|
||||
{
|
||||
return mCx;
|
||||
}
|
||||
|
|
|
@ -1835,6 +1835,7 @@ GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject)
|
|||
mCx(aCx),
|
||||
mGlobalObject(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mCx);
|
||||
JS::Rooted<JSObject*> obj(aCx, aObject);
|
||||
if (js::IsWrapper(obj)) {
|
||||
obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
|
||||
|
@ -2437,7 +2438,7 @@ ConvertExceptionToPromise(JSContext* cx,
|
|||
|
||||
JS_ClearPendingException(cx);
|
||||
ErrorResult rv;
|
||||
nsRefPtr<Promise> promise = Promise::Reject(global, cx, exn, rv);
|
||||
nsRefPtr<Promise> promise = Promise::Reject(global, exn, rv);
|
||||
if (rv.Failed()) {
|
||||
// We just give up. Make sure to not leak memory on the
|
||||
// ErrorResult, but then just put the original exception back.
|
||||
|
|
|
@ -5726,8 +5726,9 @@ def isResultAlreadyAddRefed(extendedAttributes):
|
|||
return 'resultNotAddRefed' not in extendedAttributes
|
||||
|
||||
|
||||
def needCx(returnType, arguments, extendedAttributes, considerTypes):
|
||||
return (considerTypes and
|
||||
def needCx(returnType, arguments, extendedAttributes, considerTypes,
|
||||
static=False):
|
||||
return (not static and considerTypes and
|
||||
(typeNeedsCx(returnType, True) or
|
||||
any(typeNeedsCx(a.type) for a in arguments)) or
|
||||
'implicitJSContext' in extendedAttributes)
|
||||
|
@ -6057,10 +6058,11 @@ class CGPerSignatureCall(CGThing):
|
|||
|
||||
# For JS-implemented interfaces we do not want to base the
|
||||
# needsCx decision on the types involved, just on our extended
|
||||
# attributes.
|
||||
# attributes. Also, JSContext is not needed for the static case
|
||||
# since GlobalObject already contains the context.
|
||||
needsCx = needCx(returnType, arguments, self.extendedAttributes,
|
||||
not descriptor.interface.isJSImplemented())
|
||||
if needsCx and not (static and descriptor.workers):
|
||||
not descriptor.interface.isJSImplemented(), static)
|
||||
if needsCx:
|
||||
argsPre.append("cx")
|
||||
|
||||
needsUnwrap = False
|
||||
|
@ -11708,7 +11710,7 @@ class CGNativeMember(ClassMethod):
|
|||
args.insert(0, Argument("JS::Value", "aThisVal"))
|
||||
# And jscontext bits.
|
||||
if needCx(returnType, argList, self.extendedAttrs,
|
||||
self.passJSBitsAsNeeded):
|
||||
self.passJSBitsAsNeeded, self.member.isStatic()):
|
||||
args.insert(0, Argument("JSContext*", "cx"))
|
||||
if needScopeObject(returnType, argList, self.extendedAttrs,
|
||||
self.descriptorProvider.wrapperCache,
|
||||
|
@ -13647,7 +13649,7 @@ class CGEventMethod(CGNativeMember):
|
|||
self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
|
||||
constructorForNativeCaller = CGNativeMember.declare(self, cgClass)
|
||||
self.args = list(self.originalArgs)
|
||||
if needCx(None, self.arguments(), [], True):
|
||||
if needCx(None, self.arguments(), [], considerTypes=True, static=True):
|
||||
self.args.insert(0, Argument("JSContext*", "aCx"))
|
||||
self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
|
||||
self.args.append(Argument('ErrorResult&', 'aRv'))
|
||||
|
@ -13698,7 +13700,7 @@ class CGEventMethod(CGNativeMember):
|
|||
""",
|
||||
arg0=self.args[0].name,
|
||||
arg1=self.args[1].name)
|
||||
if needCx(None, self.arguments(), [], True):
|
||||
if needCx(None, self.arguments(), [], considerTypes=True, static=True):
|
||||
self.args.insert(0, Argument("JSContext*", "aCx"))
|
||||
self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
|
||||
self.args.append(Argument('ErrorResult&', 'aRv'))
|
||||
|
|
|
@ -151,7 +151,6 @@ public:
|
|||
|
||||
static
|
||||
already_AddRefed<TestInterface> Test2(const GlobalObject&,
|
||||
JSContext*,
|
||||
const DictForConstructor&,
|
||||
JS::Handle<JS::Value>,
|
||||
JS::Handle<JSObject*>,
|
||||
|
@ -682,8 +681,7 @@ public:
|
|||
|
||||
// Static methods and attributes
|
||||
static void StaticMethod(const GlobalObject&, bool);
|
||||
static void StaticMethodWithContext(const GlobalObject&, JSContext*,
|
||||
JS::Value);
|
||||
static void StaticMethodWithContext(const GlobalObject&, JS::Value);
|
||||
static bool StaticAttribute(const GlobalObject&);
|
||||
static void SetStaticAttribute(const GlobalObject&, bool);
|
||||
|
||||
|
|
|
@ -196,7 +196,3 @@ disabled = bug 774100
|
|||
# Disabled due to focus issues (no bug that I'm aware of)
|
||||
[test_browserElement_oop_KeyEvents.html]
|
||||
disabled =
|
||||
# Disable due to certificate issue (no bug that I'm aware of)
|
||||
[test_browserElement_inproc_ErrorSecurity.html]
|
||||
skip-if = buildapp=='b2g'
|
||||
disabled =
|
||||
|
|
|
@ -523,6 +523,7 @@ void
|
|||
Event::SetEventType(const nsAString& aEventTypeArg)
|
||||
{
|
||||
if (mIsMainThreadEvent) {
|
||||
mEvent->typeString.Truncate();
|
||||
mEvent->userType =
|
||||
nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType,
|
||||
&(mEvent->message));
|
||||
|
|
|
@ -114,7 +114,7 @@ MessageEvent::GetSource(Nullable<OwningWindowProxyOrMessagePort>& aValue) const
|
|||
|
||||
/* static */ already_AddRefed<MessageEvent>
|
||||
MessageEvent::Constructor(const GlobalObject& aGlobal,
|
||||
JSContext* aCx, const nsAString& aType,
|
||||
const nsAString& aType,
|
||||
const MessageEventInit& aParam,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
}
|
||||
|
||||
static already_AddRefed<MessageEvent>
|
||||
Constructor(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const MessageEventInit& aEventInit,
|
||||
ErrorResult& aRv);
|
||||
|
|
|
@ -157,3 +157,4 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
|
|||
skip-if = buildapp == 'b2g' || e10s
|
||||
[test_bug985988.html]
|
||||
[test_dom_storage_event.html]
|
||||
[test_bug998809.html]
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=998809
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 998809</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 998809 **/
|
||||
var event1 = document.createEvent("Event");
|
||||
event1.initEvent("a", false, false);
|
||||
event1.initEvent("b", false, false);
|
||||
is(event1.type, "b");
|
||||
var event2 = document.createEvent("Event");
|
||||
event2.initEvent("a", false, false);
|
||||
is(event2.type, "a");
|
||||
event2.initEvent("b", false, false);
|
||||
is(event2.type, "b");
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=998809">Mozilla Bug 998809</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -214,7 +214,7 @@ IDBKeyRange::GetUpper(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
|
|||
|
||||
// static
|
||||
already_AddRefed<IDBKeyRange>
|
||||
IDBKeyRange::Only(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
IDBKeyRange::Only(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aValue, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
|
@ -222,7 +222,7 @@ IDBKeyRange::Only(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
nsRefPtr<IDBKeyRange> keyRange =
|
||||
new IDBKeyRange(aGlobal.GetAsSupports(), false, false, true);
|
||||
|
||||
aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower());
|
||||
aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower());
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ IDBKeyRange::Only(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
|
||||
// static
|
||||
already_AddRefed<IDBKeyRange>
|
||||
IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
IDBKeyRange::LowerBound(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aValue, bool aOpen,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
|
@ -241,7 +241,7 @@ IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
nsRefPtr<IDBKeyRange> keyRange =
|
||||
new IDBKeyRange(aGlobal.GetAsSupports(), aOpen, true, false);
|
||||
|
||||
aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower());
|
||||
aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower());
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
|
||||
// static
|
||||
already_AddRefed<IDBKeyRange>
|
||||
IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
IDBKeyRange::UpperBound(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aValue, bool aOpen,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
|
@ -260,7 +260,7 @@ IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
nsRefPtr<IDBKeyRange> keyRange =
|
||||
new IDBKeyRange(aGlobal.GetAsSupports(), true, aOpen, false);
|
||||
|
||||
aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Upper());
|
||||
aRv = GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Upper());
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
|
||||
// static
|
||||
already_AddRefed<IDBKeyRange>
|
||||
IDBKeyRange::Bound(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
IDBKeyRange::Bound(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aLower, JS::Handle<JS::Value> aUpper,
|
||||
bool aLowerOpen, bool aUpperOpen, ErrorResult& aRv)
|
||||
{
|
||||
|
@ -279,12 +279,12 @@ IDBKeyRange::Bound(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
nsRefPtr<IDBKeyRange> keyRange =
|
||||
new IDBKeyRange(aGlobal.GetAsSupports(), aLowerOpen, aUpperOpen, false);
|
||||
|
||||
aRv = GetKeyFromJSVal(aCx, aLower, keyRange->Lower());
|
||||
aRv = GetKeyFromJSVal(aGlobal.Context(), aLower, keyRange->Lower());
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aRv = GetKeyFromJSVal(aCx, aUpper, keyRange->Upper());
|
||||
aRv = GetKeyFromJSVal(aGlobal.Context(), aUpper, keyRange->Upper());
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -177,19 +177,19 @@ public:
|
|||
}
|
||||
|
||||
static already_AddRefed<IDBKeyRange>
|
||||
Only(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Only(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<IDBKeyRange>
|
||||
LowerBound(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
LowerBound(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aValue, bool aOpen, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<IDBKeyRange>
|
||||
UpperBound(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
UpperBound(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aValue, bool aOpen, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<IDBKeyRange>
|
||||
Bound(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Bound(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aLower, JS::Handle<JS::Value> aUpper,
|
||||
bool aLowerOpen, bool aUpperOpen, ErrorResult& aRv);
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ MozNDEFRecord::Constructor(const GlobalObject& aGlobal,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<MozNDEFRecord> ndefrecord = new MozNDEFRecord(aGlobal.GetContext(),
|
||||
nsRefPtr<MozNDEFRecord> ndefrecord = new MozNDEFRecord(aGlobal.Context(),
|
||||
win, aTnf, aType, aId,
|
||||
aPayload);
|
||||
if (!ndefrecord) {
|
||||
|
|
|
@ -593,7 +593,7 @@ Promise::CreateThenableFunction(JSContext* aCx, Promise* aPromise, uint32_t aTas
|
|||
Promise::Constructor(const GlobalObject& aGlobal,
|
||||
PromiseInit& aInit, ErrorResult& aRv)
|
||||
{
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global;
|
||||
global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
|
@ -641,12 +641,12 @@ Promise::Constructor(const GlobalObject& aGlobal,
|
|||
}
|
||||
|
||||
/* static */ already_AddRefed<Promise>
|
||||
Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Promise::Resolve(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aValue, ErrorResult& aRv)
|
||||
{
|
||||
// If a Promise was passed, just return it.
|
||||
if (aValue.isObject()) {
|
||||
JS::Rooted<JSObject*> valueObj(aCx, &aValue.toObject());
|
||||
JS::Rooted<JSObject*> valueObj(aGlobal.Context(), &aValue.toObject());
|
||||
Promise* nextPromise;
|
||||
nsresult rv = UNWRAP_OBJECT(Promise, valueObj, nextPromise);
|
||||
|
||||
|
@ -663,7 +663,7 @@ Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return Resolve(global, aCx, aValue, aRv);
|
||||
return Resolve(global, aGlobal.Context(), aValue, aRv);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Promise>
|
||||
|
@ -677,7 +677,7 @@ Promise::Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
|
|||
}
|
||||
|
||||
/* static */ already_AddRefed<Promise>
|
||||
Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Promise::Reject(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aValue, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global =
|
||||
|
@ -687,7 +687,7 @@ Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return Reject(global, aCx, aValue, aRv);
|
||||
return Reject(global, aGlobal.Context(), aValue, aRv);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Promise>
|
||||
|
@ -744,9 +744,9 @@ public:
|
|||
: mPromise(aPromise), mCountdown(aCountdown)
|
||||
{
|
||||
MOZ_ASSERT(aCountdown != 0);
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
// The only time aGlobal.GetContext() and aGlobal.Get() are not
|
||||
// The only time aGlobal.Context() and aGlobal.Get() are not
|
||||
// same-compartment is when we're called via Xrays, and in that situation we
|
||||
// in fact want to create the array in the callee compartment
|
||||
|
||||
|
@ -864,7 +864,7 @@ NS_INTERFACE_MAP_END_INHERITING(PromiseNativeHandler)
|
|||
NS_IMPL_CYCLE_COLLECTION(AllResolveHandler, mCountdownHolder)
|
||||
|
||||
/* static */ already_AddRefed<Promise>
|
||||
Promise::All(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Promise::All(const GlobalObject& aGlobal,
|
||||
const Sequence<JS::Value>& aIterable, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global =
|
||||
|
@ -874,21 +874,23 @@ Promise::All(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
if (aIterable.Length() == 0) {
|
||||
JS::Rooted<JSObject*> empty(aCx, JS_NewArrayObject(aCx, 0));
|
||||
JS::Rooted<JSObject*> empty(cx, JS_NewArrayObject(cx, 0));
|
||||
if (!empty) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*empty));
|
||||
return Promise::Resolve(aGlobal, aCx, value, aRv);
|
||||
JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*empty));
|
||||
return Promise::Resolve(aGlobal, value, aRv);
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = new Promise(global);
|
||||
nsRefPtr<CountdownHolder> holder =
|
||||
new CountdownHolder(aGlobal, promise, aIterable.Length());
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
JS::Rooted<JSObject*> obj(cx, JS::CurrentGlobalOrNull(cx));
|
||||
if (!obj) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
|
@ -897,8 +899,8 @@ Promise::All(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(promise, obj);
|
||||
|
||||
for (uint32_t i = 0; i < aIterable.Length(); ++i) {
|
||||
JS::Rooted<JS::Value> value(aCx, aIterable.ElementAt(i));
|
||||
nsRefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, aCx, value, aRv);
|
||||
JS::Rooted<JS::Value> value(cx, aIterable.ElementAt(i));
|
||||
nsRefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, value, aRv);
|
||||
|
||||
MOZ_ASSERT(!aRv.Failed());
|
||||
|
||||
|
@ -916,7 +918,7 @@ Promise::All(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
}
|
||||
|
||||
/* static */ already_AddRefed<Promise>
|
||||
Promise::Race(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Promise::Race(const GlobalObject& aGlobal,
|
||||
const Sequence<JS::Value>& aIterable, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global =
|
||||
|
@ -926,7 +928,9 @@ Promise::Race(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, JS::CurrentGlobalOrNull(cx));
|
||||
if (!obj) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
|
@ -940,8 +944,8 @@ Promise::Race(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(promise, obj);
|
||||
|
||||
for (uint32_t i = 0; i < aIterable.Length(); ++i) {
|
||||
JS::Rooted<JS::Value> value(aCx, aIterable.ElementAt(i));
|
||||
nsRefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, aCx, value, aRv);
|
||||
JS::Rooted<JS::Value> value(cx, aIterable.ElementAt(i));
|
||||
nsRefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, value, aRv);
|
||||
// According to spec, Resolve can throw, but our implementation never does.
|
||||
// Well it does when window isn't passed on the main thread, but that is an
|
||||
// implementation detail which should never be reached since we are checking
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<Promise>
|
||||
Resolve(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Resolve(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<Promise>
|
||||
|
@ -129,7 +129,7 @@ public:
|
|||
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<Promise>
|
||||
Reject(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Reject(const GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<Promise>
|
||||
|
@ -144,11 +144,11 @@ public:
|
|||
Catch(JSContext* aCx, AnyCallback* aRejectCallback);
|
||||
|
||||
static already_AddRefed<Promise>
|
||||
All(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
All(const GlobalObject& aGlobal,
|
||||
const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<Promise>
|
||||
Race(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Race(const GlobalObject& aGlobal,
|
||||
const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
|
||||
|
||||
void AppendNativeHandler(PromiseNativeHandler* aRunnable);
|
||||
|
|
|
@ -1502,15 +1502,11 @@ this.PushService = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Get mobile network information to decide if the client is capable of being
|
||||
* woken up by UDP (which currently just means having an mcc and mnc along
|
||||
* with an IP).
|
||||
* Returns information about MCC-MNC and the IP of the current connection.
|
||||
*/
|
||||
_getNetworkState: function(callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
throw new Error("No callback method. Aborting push agent !");
|
||||
}
|
||||
debug("getNetworkState()");
|
||||
_getNetworkInformation: function() {
|
||||
debug("getNetworkInformation()");
|
||||
|
||||
try {
|
||||
if (!prefs.get("udp.wakeupEnabled")) {
|
||||
debug("UDP support disabled, we do not send any carrier info");
|
||||
|
@ -1534,16 +1530,11 @@ this.PushService = {
|
|||
let prefixLengths = {};
|
||||
nm.active.getAddresses(ips, prefixLengths);
|
||||
|
||||
this._getMobileNetworkId(function(netid) {
|
||||
debug("Recovered netID = " + netid);
|
||||
callback({
|
||||
mcc: iccInfo.mcc,
|
||||
mnc: iccInfo.mnc,
|
||||
ip: ips.value[0],
|
||||
netid: netid
|
||||
});
|
||||
});
|
||||
return;
|
||||
return {
|
||||
mcc: iccInfo.mcc,
|
||||
mnc: iccInfo.mnc,
|
||||
ip: ips.value[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -1551,11 +1542,40 @@ this.PushService = {
|
|||
}
|
||||
|
||||
debug("Running on wifi");
|
||||
callback({
|
||||
return {
|
||||
mcc: 0,
|
||||
mnc: 0,
|
||||
ip: undefined
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Get mobile network information to decide if the client is capable of being
|
||||
* woken up by UDP (which currently just means having an mcc and mnc along
|
||||
* with an IP, and optionally a netid).
|
||||
*/
|
||||
_getNetworkState: function(callback) {
|
||||
debug("getNetworkState()");
|
||||
|
||||
if (typeof callback !== 'function') {
|
||||
throw new Error("No callback method. Aborting push agent !");
|
||||
}
|
||||
|
||||
var networkInfo = this._getNetworkInformation();
|
||||
|
||||
if (networkInfo.ip) {
|
||||
this._getMobileNetworkId(function(netid) {
|
||||
debug("Recovered netID = " + netid);
|
||||
callback({
|
||||
mcc: networkInfo.mcc,
|
||||
mnc: networkInfo.mnc,
|
||||
ip: networkInfo.ip,
|
||||
netid: netid
|
||||
});
|
||||
});
|
||||
} else {
|
||||
callback(networkInfo);
|
||||
}
|
||||
},
|
||||
|
||||
// utility function used to add/remove observers in init() and shutdown()
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aPromise);
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
JSAutoCompartment ac(cx, mGlobal);
|
||||
mNotifications = JS_NewArrayObject(cx, 0);
|
||||
HoldData();
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
* 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/. */
|
||||
|
||||
// XXX: This must be done prior to including cert.h (directly or indirectly).
|
||||
// CERT_AddTempCertToPerm is exposed as __CERT_AddTempCertToPerm.
|
||||
#define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
|
||||
|
||||
#include "WifiCertService.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
|
|
|
@ -2123,7 +2123,7 @@ RuntimeService::CreateSharedWorkerInternal(const GlobalObject& aGlobal,
|
|||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(window);
|
||||
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
WorkerPrivate::LoadInfo loadInfo;
|
||||
nsresult rv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL,
|
||||
|
|
|
@ -475,7 +475,7 @@ URL*
|
|||
URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
URL& aBase, ErrorResult& aRv)
|
||||
{
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
|
||||
|
||||
nsRefPtr<ConstructorRunnable> runnable =
|
||||
|
@ -499,7 +499,7 @@ URL*
|
|||
URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
const nsAString& aBase, ErrorResult& aRv)
|
||||
{
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
|
||||
|
||||
nsRefPtr<ConstructorRunnable> runnable =
|
||||
|
@ -844,7 +844,7 @@ URL::CreateObjectURL(const GlobalObject& aGlobal, JSObject* aBlob,
|
|||
const mozilla::dom::objectURLOptions& aOptions,
|
||||
nsString& aResult, mozilla::ErrorResult& aRv)
|
||||
{
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = file::GetDOMBlobFromJSObject(aBlob);
|
||||
|
@ -878,7 +878,7 @@ URL::CreateObjectURL(const GlobalObject& aGlobal, JSObject& aBlob,
|
|||
void
|
||||
URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl)
|
||||
{
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
|
||||
|
||||
nsRefPtr<RevokeURLRunnable> runnable =
|
||||
|
|
|
@ -3629,7 +3629,7 @@ WorkerPrivate::Constructor(const GlobalObject& aGlobal,
|
|||
const nsACString& aSharedWorkerName,
|
||||
LoadInfo* aLoadInfo, ErrorResult& aRv)
|
||||
{
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
return Constructor(cx, aScriptURL, aIsChromeWorker, aWorkerType,
|
||||
aSharedWorkerName, aLoadInfo, aRv);
|
||||
}
|
||||
|
@ -5771,7 +5771,7 @@ WorkerPrivate::ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial)
|
|||
ErrorResult rv;
|
||||
|
||||
nsRefPtr<MessageEvent> event =
|
||||
MessageEvent::Constructor(globalObject, aCx,
|
||||
MessageEvent::Constructor(globalObject,
|
||||
NS_LITERAL_STRING("connect"), init, rv);
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
|
|
@ -1627,7 +1627,7 @@ XMLHttpRequest::Constructor(const GlobalObject& aGlobal,
|
|||
const MozXMLHttpRequestParameters& aParams,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
JSContext* cx = aGlobal.Context();
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ public:
|
|||
{
|
||||
// Pretend like someone passed null, so we can pick up the default values
|
||||
MozXMLHttpRequestParameters params;
|
||||
if (!params.Init(aGlobal.GetContext(), JS::NullHandleValue)) {
|
||||
if (!params.Init(aGlobal.Context(), JS::NullHandleValue)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,9 @@ In this order:
|
|||
angle-d3dcc47.patch:
|
||||
Tell ANGLE about d3dcompiler_47.dll from WinSDK 8.1.
|
||||
|
||||
angle-fix-issue-651.patch:
|
||||
Fixes crash in TSymbolTableLevel::~TSymbolTableLevel with GCC 4.9
|
||||
|
||||
In addition to these patches, the Makefile.in and moz.build build files are ours,
|
||||
they're not present in upsteam ANGLE. Therefore, changes made to the build files
|
||||
should not be stored in the local .patch files.
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
Fix for https://code.google.com/p/angleproject/issues/detail?id=651
|
||||
|
||||
See https://bugzilla.mozilla.org/show_bug.cgi?id=1025576 for details.
|
||||
|
||||
diff --git a/gfx/angle/src/compiler/SymbolTable.cpp b/gfx/angle/src/compiler/SymbolTable.cpp
|
||||
--- a/gfx/angle/src/compiler/SymbolTable.cpp
|
||||
+++ b/gfx/angle/src/compiler/SymbolTable.cpp
|
||||
@@ -166,17 +166,18 @@ TFunction::~TFunction()
|
||||
}
|
||||
|
||||
//
|
||||
// Symbol table levels are a map of pointers to symbols that have to be deleted.
|
||||
//
|
||||
TSymbolTableLevel::~TSymbolTableLevel()
|
||||
{
|
||||
for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
|
||||
- delete (*it).second;
|
||||
+ if ((*it).first == (*it).second->getMangledName())
|
||||
+ delete (*it).second;
|
||||
}
|
||||
|
||||
//
|
||||
// Change all function entries in the table with the non-mangled name
|
||||
// to be related to the provided built-in operation. This is a low
|
||||
// performance operation, and only intended for symbol tables that
|
||||
// live across a large number of compiles.
|
||||
//
|
|
@ -171,7 +171,8 @@ TFunction::~TFunction()
|
|||
TSymbolTableLevel::~TSymbolTableLevel()
|
||||
{
|
||||
for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
|
||||
delete (*it).second;
|
||||
if ((*it).first == (*it).second->getMangledName())
|
||||
delete (*it).second;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "gfxPlatform.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "GLUploadHelpers.h"
|
||||
|
||||
|
|
|
@ -220,6 +220,10 @@ GrallocImage::GetAsSourceSurface()
|
|||
|
||||
RefPtr<gfx::DataSourceSurface> surface
|
||||
= gfx::Factory::CreateDataSourceSurface(GetSize(), gfx::SurfaceFormat::R5G6B5);
|
||||
if (!surface) {
|
||||
NS_WARNING("Failed to create SourceSurface.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t width = GetSize().width;
|
||||
uint32_t height = GetSize().height;
|
||||
|
|
|
@ -575,6 +575,10 @@ PlanarYCbCrImage::GetAsSourceSurface()
|
|||
}
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(size, format);
|
||||
if (!surface) {
|
||||
NS_WARNING("Failed to create SourceSurface.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gfx::ConvertYCbCrToRGB(mData, format, size, surface->GetData(), surface->Stride());
|
||||
|
||||
|
@ -590,6 +594,10 @@ RemoteBitmapImage::GetAsSourceSurface()
|
|||
? gfx::SurfaceFormat::B8G8R8X8
|
||||
: gfx::SurfaceFormat::B8G8R8A8;
|
||||
RefPtr<gfx::DataSourceSurface> newSurf = gfx::Factory::CreateDataSourceSurface(mSize, fmt);
|
||||
if (!newSurf) {
|
||||
NS_WARNING("Failed to create SourceSurface.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (int y = 0; y < mSize.height; y++) {
|
||||
memcpy(newSurf->GetData() + newSurf->Stride() * y,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "mozilla/DebugOnly.h" // for DebugOnly
|
||||
#include "mozilla/Telemetry.h" // for Accumulate
|
||||
#include "mozilla/gfx/2D.h" // for DrawTarget
|
||||
|
|
|
@ -276,6 +276,10 @@ YCbCrImageDataDeserializer::ToDataSourceSurface()
|
|||
{
|
||||
RefPtr<DataSourceSurface> result =
|
||||
Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8);
|
||||
if (!result) {
|
||||
NS_WARNING("Failed to create SourceSurface.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
result->Map(DataSourceSurface::MapType::WRITE, &map);
|
||||
|
|
|
@ -8,11 +8,9 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "inIDOMUtils.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/task.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
#define AEM_LOG(...)
|
||||
// #define AEM_LOG(...) printf_stderr("AEM: " __VA_ARGS__)
|
||||
|
@ -40,7 +38,7 @@ ActiveElementManager::ActiveElementManager()
|
|||
ActiveElementManager::~ActiveElementManager() {}
|
||||
|
||||
void
|
||||
ActiveElementManager::SetTargetElement(nsIDOMEventTarget* aTarget)
|
||||
ActiveElementManager::SetTargetElement(dom::EventTarget* aTarget)
|
||||
{
|
||||
if (mTarget) {
|
||||
// Multiple fingers on screen (since HandleTouchEnd clears mTarget).
|
||||
|
@ -126,11 +124,12 @@ ActiveElementManager::HandleTouchEnd(bool aWasClick)
|
|||
}
|
||||
|
||||
void
|
||||
ActiveElementManager::SetActive(nsIDOMElement* aTarget)
|
||||
ActiveElementManager::SetActive(dom::Element* aTarget)
|
||||
{
|
||||
AEM_LOG("Setting active %p\n", aTarget);
|
||||
if (mDomUtils) {
|
||||
mDomUtils->SetContentState(aTarget, NS_EVENT_STATE_ACTIVE.GetInternalValue());
|
||||
nsCOMPtr<nsIDOMElement> target = do_QueryInterface(aTarget);
|
||||
mDomUtils->SetContentState(target, NS_EVENT_STATE_ACTIVE.GetInternalValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,15 +140,10 @@ ActiveElementManager::ResetActive()
|
|||
|
||||
// Clear the :active flag from mTarget by setting it on the document root.
|
||||
if (mTarget) {
|
||||
nsCOMPtr<nsIDOMDocument> doc;
|
||||
mTarget->GetOwnerDocument(getter_AddRefs(doc));
|
||||
if (doc) {
|
||||
nsCOMPtr<nsIDOMElement> root;
|
||||
doc->GetDocumentElement(getter_AddRefs(root));
|
||||
if (root) {
|
||||
AEM_LOG("Found root %p, making active\n", root.get());
|
||||
SetActive(root);
|
||||
}
|
||||
dom::Element* root = mTarget->OwnerDoc()->GetDocumentElement();
|
||||
if (root) {
|
||||
AEM_LOG("Found root %p, making active\n", root.get());
|
||||
SetActive(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -162,7 +156,7 @@ ActiveElementManager::ResetTouchBlockState()
|
|||
}
|
||||
|
||||
void
|
||||
ActiveElementManager::SetActiveTask(nsIDOMElement* aTarget)
|
||||
ActiveElementManager::SetActiveTask(dom::Element* aTarget)
|
||||
{
|
||||
AEM_LOG("mSetActiveTask %p running\n", mSetActiveTask);
|
||||
|
||||
|
|
|
@ -10,11 +10,14 @@
|
|||
#include "nsISupportsImpl.h"
|
||||
|
||||
class inIDOMUtils;
|
||||
class nsIDOMEventTarget;
|
||||
class nsIDOMElement;
|
||||
class CancelableTask;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Element;
|
||||
class EventTarget;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
|
@ -35,7 +38,7 @@ public:
|
|||
* HandleTouchStart().
|
||||
* |aTarget| may be nullptr.
|
||||
*/
|
||||
void SetTargetElement(nsIDOMEventTarget* aTarget);
|
||||
void SetTargetElement(dom::EventTarget* aTarget);
|
||||
/**
|
||||
* Handle a touch-start event.
|
||||
* @param aCanBePan whether the touch can be a pan
|
||||
|
@ -55,7 +58,7 @@ private:
|
|||
/**
|
||||
* The target of the first touch point in the current touch block.
|
||||
*/
|
||||
nsCOMPtr<nsIDOMElement> mTarget;
|
||||
nsCOMPtr<dom::Element> mTarget;
|
||||
/**
|
||||
* Whether the current touch block can be a pan. Set in HandleTouchStart().
|
||||
*/
|
||||
|
@ -73,10 +76,10 @@ private:
|
|||
|
||||
// Helpers
|
||||
void TriggerElementActivation();
|
||||
void SetActive(nsIDOMElement* aTarget);
|
||||
void SetActive(dom::Element* aTarget);
|
||||
void ResetActive();
|
||||
void ResetTouchBlockState();
|
||||
void SetActiveTask(nsIDOMElement* aTarget);
|
||||
void SetActiveTask(dom::Element* aTarget);
|
||||
void CancelTask();
|
||||
};
|
||||
|
||||
|
|
|
@ -85,6 +85,9 @@ TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin,
|
|||
// Create a surface to draw our glyphs to.
|
||||
RefPtr<DataSourceSurface> textSurf =
|
||||
Factory::CreateDataSourceSurface(IntSize(maxWidth, numLines * sCellHeight), sTextureFormat);
|
||||
if (!textSurf) {
|
||||
return;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map);
|
||||
|
@ -144,6 +147,10 @@ TextRenderer::EnsureInitialized()
|
|||
}
|
||||
|
||||
mGlyphBitmaps = Factory::CreateDataSourceSurface(IntSize(sTextureWidth, sTextureHeight), sTextureFormat);
|
||||
if (!mGlyphBitmaps) {
|
||||
NS_WARNING("Failed to create SourceSurface.");
|
||||
return;
|
||||
}
|
||||
|
||||
mGlyphBitmaps->Map(DataSourceSurface::MapType::READ_WRITE, &mMap);
|
||||
|
||||
|
|
|
@ -684,7 +684,9 @@ CompositorParent::ForceComposeToTarget(DrawTarget* aTarget, const nsIntRect* aRe
|
|||
bool
|
||||
CompositorParent::CanComposite()
|
||||
{
|
||||
return !(mPaused || !mLayerManager || !mLayerManager->GetRoot());
|
||||
return mLayerManager &&
|
||||
mLayerManager->GetRoot() &&
|
||||
!mPaused;
|
||||
}
|
||||
|
||||
// Go down the composite layer tree, setting properties to match their
|
||||
|
|
|
@ -1455,6 +1455,10 @@ CompositorOGL::CopyToTarget(DrawTarget* aTarget, const nsIntPoint& aTopLeft, con
|
|||
|
||||
RefPtr<DataSourceSurface> source =
|
||||
Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8);
|
||||
if (!source) {
|
||||
NS_WARNING("Failed to create SourceSurface.");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadPixelsIntoDataSurface(mGLContext, source);
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@ typedef uint32_t nscolor;
|
|||
#define NS_RGBA(_r,_g,_b,_a) \
|
||||
((nscolor) (((_a) << 24) | ((_b)<<16) | ((_g)<<8) | (_r)))
|
||||
|
||||
// Make a color out of a gfxRGBA.
|
||||
#define NS_RGBA_FROM_GFXRGBA(gfxColor) \
|
||||
((nscolor) (gfxColor.Packed()))
|
||||
|
||||
// Extract color components from nscolor
|
||||
#define NS_GET_R(_rgba) ((uint8_t) ((_rgba) & 0xff))
|
||||
#define NS_GET_G(_rgba) ((uint8_t) (((_rgba) >> 8) & 0xff))
|
||||
|
|
|
@ -7,12 +7,10 @@
|
|||
#include "nsISupports.idl"
|
||||
|
||||
%{C++
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxRect.h"
|
||||
#include "GraphicsFilter.h"
|
||||
#include "gfxASurface.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsRect.h"
|
||||
|
@ -41,9 +39,6 @@ class Orientation;
|
|||
|
||||
%}
|
||||
|
||||
[ptr] native gfxImageSurface(gfxImageSurface);
|
||||
[ptr] native gfxASurface(gfxASurface);
|
||||
native gfxImageFormat(gfxASurface::gfxImageFormat);
|
||||
[ptr] native gfxContext(gfxContext);
|
||||
[ref] native gfxMatrix(gfxMatrix);
|
||||
[ref] native gfxRect(gfxRect);
|
||||
|
@ -176,8 +171,7 @@ interface imgIContainer : nsISupports
|
|||
/**
|
||||
* Get a surface for the given frame. This may be a platform-native,
|
||||
* optimized surface, so you cannot inspect its pixel data. If you
|
||||
* need that, use gfxASurface::GetAsReadableARGB32ImageSurface or
|
||||
* gfxASurface::CopyToARGB32ImageSurface.
|
||||
* need that, use SourceSurface::GetDataSurface.
|
||||
*
|
||||
* @param aWhichFrame Frame specifier of the FRAME_* variety.
|
||||
* @param aFlags Flags of the FLAG_* variety
|
||||
|
|
|
@ -211,13 +211,16 @@ public:
|
|||
|
||||
bool success = false;
|
||||
if (!dstLocked) {
|
||||
// We need to hold a lock onto the RasterImage object itself so that
|
||||
// it (and its associated imgFrames) aren't marked as discardable.
|
||||
bool imgLocked = NS_SUCCEEDED(image->LockImage());
|
||||
bool srcLocked = NS_SUCCEEDED(srcFrame->LockImageData());
|
||||
srcSurface = srcFrame->GetSurface();
|
||||
|
||||
dstLocked = NS_SUCCEEDED(dstFrame->LockImageData());
|
||||
dstSurface = dstFrame->GetSurface();
|
||||
|
||||
success = srcLocked && dstLocked && srcSurface && dstSurface;
|
||||
success = imgLocked && srcLocked && dstLocked && srcSurface && dstSurface;
|
||||
|
||||
if (success) {
|
||||
srcData = srcFrame->GetImageData();
|
||||
|
@ -253,6 +256,7 @@ public:
|
|||
if (DiscardingEnabled())
|
||||
dstFrame->SetDiscardable();
|
||||
success = NS_SUCCEEDED(dstFrame->UnlockImageData());
|
||||
success = success && NS_SUCCEEDED(image->UnlockImage());
|
||||
|
||||
dstLocked = false;
|
||||
srcData = nullptr;
|
||||
|
@ -346,9 +350,9 @@ public:
|
|||
ScaleRequest* request = mScaleRequest;
|
||||
|
||||
if (!request->stopped) {
|
||||
request->done = mozilla::gfx::Scale(request->srcData, request->srcRect.width, request->srcRect.height, request->srcStride,
|
||||
request->dstData, request->dstSize.width, request->dstSize.height, request->dstStride,
|
||||
request->srcFormat);
|
||||
request->done = gfx::Scale(request->srcData, request->srcRect.width, request->srcRect.height, request->srcStride,
|
||||
request->dstData, request->dstSize.width, request->dstSize.height, request->dstStride,
|
||||
request->srcFormat);
|
||||
} else {
|
||||
request->done = false;
|
||||
}
|
||||
|
@ -535,7 +539,7 @@ RasterImage::Init(const char* aMimeType,
|
|||
//******************************************************************************
|
||||
// [notxpcom] void requestRefresh ([const] in TimeStamp aTime);
|
||||
NS_IMETHODIMP_(void)
|
||||
RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime)
|
||||
RasterImage::RequestRefresh(const TimeStamp& aTime)
|
||||
{
|
||||
if (HadRecentRefresh(aTime)) {
|
||||
return;
|
||||
|
@ -1568,7 +1572,7 @@ RasterImage::ResetAnimation()
|
|||
//******************************************************************************
|
||||
// [notxpcom] void setAnimationStartTime ([const] in TimeStamp aTime);
|
||||
NS_IMETHODIMP_(void)
|
||||
RasterImage::SetAnimationStartTime(const mozilla::TimeStamp& aTime)
|
||||
RasterImage::SetAnimationStartTime(const TimeStamp& aTime)
|
||||
{
|
||||
if (mError || mAnimationMode == kDontAnimMode || mAnimating || !mAnim)
|
||||
return;
|
||||
|
@ -3232,7 +3236,7 @@ RasterImage::DecodePool::DecodePool()
|
|||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
|
||||
nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
|
||||
if (obsSvc) {
|
||||
obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
|
||||
}
|
||||
|
|
|
@ -176,8 +176,8 @@ public:
|
|||
/* The total number of frames in this image. */
|
||||
uint32_t GetNumFrames() const;
|
||||
|
||||
virtual size_t HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
virtual size_t HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
|
||||
virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
|
||||
virtual size_t NonHeapSizeOfDecoded() const;
|
||||
virtual size_t OutOfProcessSizeOfDecoded() const;
|
||||
|
||||
|
@ -497,7 +497,7 @@ private:
|
|||
// mThreadPoolMutex protects mThreadPool. For all RasterImages R,
|
||||
// R::mDecodingMonitor must be acquired before mThreadPoolMutex
|
||||
// if both are acquired; the other order may cause deadlock.
|
||||
mozilla::Mutex mThreadPoolMutex;
|
||||
Mutex mThreadPoolMutex;
|
||||
nsCOMPtr<nsIThreadPool> mThreadPool;
|
||||
};
|
||||
|
||||
|
@ -577,7 +577,7 @@ private:
|
|||
uint32_t GetCurrentImgFrameIndex() const;
|
||||
|
||||
size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
|
||||
mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
void EnsureAnimExists();
|
||||
|
||||
|
@ -660,10 +660,10 @@ private: // data
|
|||
int mRequestedSampleSize;
|
||||
|
||||
// Cached value for GetImageContainer.
|
||||
nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
|
||||
nsRefPtr<layers::ImageContainer> mImageContainer;
|
||||
|
||||
// If not cached in mImageContainer, this might have our image container
|
||||
WeakPtr<mozilla::layers::ImageContainer> mImageContainerCache;
|
||||
WeakPtr<layers::ImageContainer> mImageContainerCache;
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32_t mFramesNotified;
|
||||
|
@ -673,7 +673,7 @@ private: // data
|
|||
// at once, and hence need to be locked by mDecodingMonitor.
|
||||
|
||||
// BEGIN LOCKED MEMBER VARIABLES
|
||||
mozilla::ReentrantMonitor mDecodingMonitor;
|
||||
ReentrantMonitor mDecodingMonitor;
|
||||
|
||||
FallibleTArray<char> mSourceData;
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxASurface.h"
|
||||
#include "gfxPattern.h" // Workaround for flaw in bug 921753 part 2.
|
||||
#include "gfxDrawable.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
static bool gDisableOptimize = false;
|
||||
|
||||
#include "cairo.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
imgFrame();
|
||||
~imgFrame();
|
||||
|
||||
nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, mozilla::gfx::SurfaceFormat aFormat, uint8_t aPaletteDepth = 0);
|
||||
nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, SurfaceFormat aFormat, uint8_t aPaletteDepth = 0);
|
||||
nsresult Optimize();
|
||||
|
||||
bool Draw(gfxContext *aContext, GraphicsFilter aFilter,
|
||||
|
@ -36,7 +36,7 @@ public:
|
|||
nsresult ImageUpdated(const nsIntRect &aUpdateRect);
|
||||
|
||||
nsIntRect GetRect() const;
|
||||
mozilla::gfx::SurfaceFormat GetFormat() const;
|
||||
SurfaceFormat GetFormat() const;
|
||||
bool GetNeedsBackground() const;
|
||||
uint32_t GetImageBytesPerRow() const;
|
||||
uint32_t GetImageDataLength() const;
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
@ -432,47 +430,6 @@ class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertOnGC
|
|||
explicit AutoCheckCannotGC(JSRuntime *rt) : AutoAssertOnGC(rt) {}
|
||||
};
|
||||
|
||||
class JS_PUBLIC_API(ObjectPtr)
|
||||
{
|
||||
Heap<JSObject *> value;
|
||||
|
||||
public:
|
||||
ObjectPtr() : value(nullptr) {}
|
||||
|
||||
explicit ObjectPtr(JSObject *obj) : value(obj) {}
|
||||
|
||||
/* Always call finalize before the destructor. */
|
||||
~ObjectPtr() { MOZ_ASSERT(!value); }
|
||||
|
||||
void finalize(JSRuntime *rt) {
|
||||
if (IsIncrementalBarrierNeeded(rt))
|
||||
IncrementalObjectBarrier(value);
|
||||
value = nullptr;
|
||||
}
|
||||
|
||||
void init(JSObject *obj) { value = obj; }
|
||||
|
||||
JSObject *get() const { return value; }
|
||||
|
||||
void writeBarrierPre(JSRuntime *rt) {
|
||||
IncrementalObjectBarrier(value);
|
||||
}
|
||||
|
||||
bool isAboutToBeFinalized();
|
||||
|
||||
ObjectPtr &operator=(JSObject *obj) {
|
||||
IncrementalObjectBarrier(value);
|
||||
value = obj;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void trace(JSTracer *trc, const char *name);
|
||||
|
||||
JSObject &operator*() const { return *value; }
|
||||
JSObject *operator->() const { return value; }
|
||||
operator JSObject *() const { return value; }
|
||||
};
|
||||
|
||||
/*
|
||||
* Unsets the gray bit for anything reachable from |thing|. |kind| should not be
|
||||
* JSTRACE_SHAPE. |thing| should be non-null.
|
||||
|
@ -507,13 +464,6 @@ ExposeGCThingToActiveJS(void *thing, JSGCTraceKind kind)
|
|||
UnmarkGrayGCThingRecursively(thing, kind);
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
ExposeValueToActiveJS(const Value &v)
|
||||
{
|
||||
if (v.isMarkable())
|
||||
ExposeGCThingToActiveJS(v.toGCThing(), v.gcKind());
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
ExposeObjectToActiveJS(JSObject *obj)
|
||||
{
|
||||
|
|
|
@ -349,7 +349,6 @@ struct RuntimeSizes
|
|||
macro(_, _, contexts) \
|
||||
macro(_, _, dtoa) \
|
||||
macro(_, _, temporary) \
|
||||
macro(_, _, regexpData) \
|
||||
macro(_, _, interpreterStack) \
|
||||
macro(_, _, mathCache) \
|
||||
macro(_, _, sourceDataCache) \
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Utility.h"
|
||||
|
@ -1165,6 +1166,47 @@ class PersistentRooted : private mozilla::LinkedListElement<PersistentRooted<T>
|
|||
T ptr;
|
||||
};
|
||||
|
||||
class JS_PUBLIC_API(ObjectPtr)
|
||||
{
|
||||
Heap<JSObject *> value;
|
||||
|
||||
public:
|
||||
ObjectPtr() : value(nullptr) {}
|
||||
|
||||
explicit ObjectPtr(JSObject *obj) : value(obj) {}
|
||||
|
||||
/* Always call finalize before the destructor. */
|
||||
~ObjectPtr() { MOZ_ASSERT(!value); }
|
||||
|
||||
void finalize(JSRuntime *rt) {
|
||||
if (IsIncrementalBarrierNeeded(rt))
|
||||
IncrementalObjectBarrier(value);
|
||||
value = nullptr;
|
||||
}
|
||||
|
||||
void init(JSObject *obj) { value = obj; }
|
||||
|
||||
JSObject *get() const { return value; }
|
||||
|
||||
void writeBarrierPre(JSRuntime *rt) {
|
||||
IncrementalObjectBarrier(value);
|
||||
}
|
||||
|
||||
bool isAboutToBeFinalized();
|
||||
|
||||
ObjectPtr &operator=(JSObject *obj) {
|
||||
IncrementalObjectBarrier(value);
|
||||
value = obj;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void trace(JSTracer *trc, const char *name);
|
||||
|
||||
JSObject &operator*() const { return *value; }
|
||||
JSObject *operator->() const { return value; }
|
||||
operator JSObject *() const { return value; }
|
||||
};
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
namespace js {
|
||||
|
|
|
@ -0,0 +1,462 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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 js_UbiNode_h
|
||||
#define js_UbiNode_h
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
// JS::ubi::Node
|
||||
//
|
||||
// JS::ubi::Node is a pointer-like type designed for internal use by heap
|
||||
// analysis tools. A ubi::Node can refer to:
|
||||
//
|
||||
// - a JS value, like a string or object;
|
||||
// - an internal SpiderMonkey structure, like a shape or a scope chain object
|
||||
// - an instance of some embedding-provided type: in Firefox, an XPCOM
|
||||
// object, or an internal DOM node class instance
|
||||
//
|
||||
// A ubi::Node instance provides metadata about its referent, and can
|
||||
// enumerate its referent's outgoing edges, so you can implement heap analysis
|
||||
// algorithms that walk the graph - finding paths between objects, or
|
||||
// computing heap dominator trees, say - using ubi::Node, while remaining
|
||||
// ignorant of the details of the types you're operating on.
|
||||
//
|
||||
// Of course, when it comes to presenting the results in a developer-facing
|
||||
// tool, you'll need to stop being ignorant of those details, because you have
|
||||
// to discuss the ubi::Nodes' referents with the developer. Here, ubi::Node
|
||||
// can hand you dynamically checked, properly typed pointers to the original
|
||||
// objects via the as<T> method, or generate descriptions of the referent
|
||||
// itself.
|
||||
//
|
||||
// ubi::Node instances are lightweight (two-word) value types. Instances:
|
||||
// - compare equal if and only if they refer to the same object;
|
||||
// - have hash values that respect their equality relation; and
|
||||
// - have serializations that are only equal if the ubi::Nodes are equal.
|
||||
//
|
||||
// A ubi::Node is only valid for as long as its referent is alive; if its
|
||||
// referent goes away, the ubi::Node becomes a dangling pointer. A ubi::Node
|
||||
// that refers to a GC-managed object is not automatically a GC root; if the
|
||||
// GC frees or relocates its referent, the ubi::Node becomes invalid. A
|
||||
// ubi::Node that refers to a reference-counted object does not bump the
|
||||
// reference count.
|
||||
//
|
||||
// ubi::Node values require no supporting data structures, making them
|
||||
// feasible for use in memory-constrained devices --- ideally, the memory
|
||||
// requirements of the algorithm which uses them will be the limiting factor,
|
||||
// not the demands of ubi::Node itself.
|
||||
//
|
||||
// One can construct a ubi::Node value given a pointer to a type that ubi::Node
|
||||
// supports. In the other direction, one can convert a ubi::Node back to a
|
||||
// pointer; these downcasts are checked dynamically. In particular, one can
|
||||
// convert a 'JSRuntime *' to a ubi::Node, yielding a node with an outgoing edge
|
||||
// for every root registered with the runtime; starting from this, one can walk
|
||||
// the entire heap. (Of course, one could also start traversal at any other kind
|
||||
// of type to which one has a pointer.)
|
||||
//
|
||||
//
|
||||
// Extending ubi::Node To Handle Your Embedding's Types
|
||||
//
|
||||
// To add support for a new ubi::Node referent type R, you must define a
|
||||
// specialization of the ubi::Concrete template, ubi::Concrete<R>, which
|
||||
// inherits from ubi::Base. ubi::Node itself uses the specialization for
|
||||
// compile-time information (i.e. the checked conversions between R * and
|
||||
// ubi::Node), and the inheritance for run-time dispatching.
|
||||
//
|
||||
//
|
||||
// ubi::Node Exposes Implementation Details
|
||||
//
|
||||
// In many cases, a JavaScript developer's view of their data differs
|
||||
// substantially from its actual implementation. For example, while the
|
||||
// ECMAScript specification describes objects as maps from property names to
|
||||
// sets of attributes (like ECMAScript's [[Value]]), in practice many objects
|
||||
// have only a pointer to a shape, shared with other similar objects, and
|
||||
// indexed slots that contain the [[Value]] attributes. As another example, a
|
||||
// string produced by concatenating two other strings may sometimes be
|
||||
// represented by a "rope", a structure that points to the two original
|
||||
// strings.
|
||||
//
|
||||
|
||||
// We intend to use ubi::Node to write tools that report memory usage, so it's
|
||||
// important that ubi::Node accurately portray how much memory nodes consume.
|
||||
// Thus, for example, when data that apparently belongs to multiple nodes is
|
||||
// in fact shared in a common structure, ubi::Node's graph uses a separate
|
||||
// node for that shared structure, and presents edges to it from the data's
|
||||
// apparent owners. For example, ubi::Node exposes SpiderMonkey objects'
|
||||
// shapes and base shapes, and exposes rope string and substring structure,
|
||||
// because these optimizations become visible when a tool reports how much
|
||||
// memory a structure consumes.
|
||||
//
|
||||
// However, fine granularity is not a goal. When a particular object is the
|
||||
// exclusive owner of a separate block of memory, ubi::Node may present the
|
||||
// object and its block as a single node, and add their sizes together when
|
||||
// reporting the node's size, as there is no meaningful loss of data in this
|
||||
// case. Thus, for example, a ubi::Node referring to a JavaScript object, when
|
||||
// asked for the object's size in bytes, includes the object's slot and
|
||||
// element arrays' sizes in the total. There is no separate ubi::Node value
|
||||
// representing the slot and element arrays, since they are owned exclusively
|
||||
// by the object.
|
||||
//
|
||||
//
|
||||
// Presenting Analysis Results To JavaScript Developers
|
||||
//
|
||||
// If an analysis provides its results in terms of ubi::Node values, a user
|
||||
// interface presenting those results will generally need to clean them up
|
||||
// before they can be understood by JavaScript developers. For example,
|
||||
// JavaScript developers should not need to understand shapes, only JavaScript
|
||||
// objects. Similarly, they should not need to understand the distinction
|
||||
// between DOM nodes and the JavaScript shadow objects that represent them.
|
||||
//
|
||||
//
|
||||
// Rooting Restrictions
|
||||
//
|
||||
// At present there is no way to root ubi::Node instances, so instances can't be
|
||||
// live across any operation that might GC. Analyses using ubi::Node must either
|
||||
// run to completion and convert their results to some other rootable type, or
|
||||
// save their intermediate state in some rooted structure if they must GC before
|
||||
// they complete. (For algorithms like path-finding and dominator tree
|
||||
// computation, we implement the algorithm avoiding any operation that could
|
||||
// cause a GC --- and use AutoCheckCannotGC to verify this.)
|
||||
//
|
||||
// If this restriction prevents us from implementing interesting tools, we may
|
||||
// teach the GC how to root ubi::Nodes, fix up hash tables that use them as
|
||||
// keys, etc.
|
||||
|
||||
|
||||
// Forward declarations of SpiderMonkey's ubi::Node reference types.
|
||||
namespace js {
|
||||
class LazyScript;
|
||||
class Shape;
|
||||
class BaseShape;
|
||||
namespace jit {
|
||||
class JitCode;
|
||||
}
|
||||
namespace types {
|
||||
struct TypeObject;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace JS {
|
||||
namespace ubi {
|
||||
|
||||
class Edge;
|
||||
class EdgeRange;
|
||||
|
||||
// The base class implemented by each ubi::Node referent type. Subclasses must
|
||||
// not add data members to this class.
|
||||
class Base {
|
||||
friend class Node;
|
||||
|
||||
// For performance's sake, we'd prefer to avoid a virtual destructor; and
|
||||
// an empty constructor seems consistent with the 'lightweight value type'
|
||||
// visible behavior we're trying to achieve. But if the destructor isn't
|
||||
// virtual, and a subclass overrides it, the subclass's destructor will be
|
||||
// ignored. Is there a way to make the compiler catch that error?
|
||||
|
||||
protected:
|
||||
// Space for the actual pointer. Concrete subclasses should define a
|
||||
// properly typed 'get' member function to access this.
|
||||
void *ptr;
|
||||
|
||||
Base(void *ptr) : ptr(ptr) { }
|
||||
|
||||
public:
|
||||
bool operator==(const Base &rhs) const {
|
||||
// Some compilers will indeed place objects of different types at
|
||||
// the same address, so technically, we should include the vtable
|
||||
// in this comparison. But it seems unlikely to cause problems in
|
||||
// practice.
|
||||
return ptr == rhs.ptr;
|
||||
}
|
||||
bool operator!=(const Base &rhs) const { return !(*this == rhs); }
|
||||
|
||||
// Return a human-readable name for the referent's type. The result should
|
||||
// be statically allocated. (You can use MOZ_UTF16("strings") for this.)
|
||||
//
|
||||
// This must always return Concrete<T>::concreteTypeName; we use that
|
||||
// pointer as a tag for this particular referent type.
|
||||
virtual const jschar *typeName() const = 0;
|
||||
|
||||
// Return the size of this node, in bytes. Include any structures that this
|
||||
// node owns exclusively that are not exposed as their own ubi::Nodes.
|
||||
virtual size_t size() const = 0;
|
||||
|
||||
// Return an EdgeRange that initially contains all the referent's outgoing
|
||||
// edges. The EdgeRange should be freed with 'js_delete'. (You could use
|
||||
// ScopedDJSeletePtr<EdgeRange> to manage it.) On OOM, report an exception
|
||||
// on |cx| and return nullptr.
|
||||
virtual EdgeRange *edges(JSContext *cx) const = 0;
|
||||
|
||||
private:
|
||||
Base(const Base &rhs) MOZ_DELETE;
|
||||
Base &operator=(const Base &rhs) MOZ_DELETE;
|
||||
};
|
||||
|
||||
// A traits template with a specialization for each referent type that
|
||||
// ubi::Node supports. The specialization must be the concrete subclass of
|
||||
// Base that represents a pointer to the referent type. It must also
|
||||
// include the members described here.
|
||||
template<typename Referent>
|
||||
struct Concrete {
|
||||
// The specific jschar array returned by Concrete<T>::typeName.
|
||||
static const jschar concreteTypeName[];
|
||||
|
||||
// Construct an instance of this concrete class in |storage| referring
|
||||
// to |referent|. Implementations typically use a placement 'new'.
|
||||
//
|
||||
// In some cases, |referent| will contain dynamic type information that
|
||||
// identifies it a some more specific subclass of |Referent|. For example,
|
||||
// when |Referent| is |JSObject|, then |referent->getClass()| could tell us
|
||||
// that it's actually a JSFunction. Similarly, if |Referent| is
|
||||
// |nsISupports|, we would like a ubi::Node that knows its final
|
||||
// implementation type.
|
||||
//
|
||||
// So, we delegate the actual construction to this specialization, which
|
||||
// knows Referent's details.
|
||||
static void construct(void *storage, Referent *referent);
|
||||
};
|
||||
|
||||
// A container for a Base instance; all members simply forward to the contained instance.
|
||||
// This container allows us to pass ubi::Node instances by value.
|
||||
class Node {
|
||||
// Storage in which we allocate Base subclasses.
|
||||
mozilla::AlignedStorage2<Base> storage;
|
||||
Base *base() { return storage.addr(); }
|
||||
const Base *base() const { return storage.addr(); }
|
||||
|
||||
template<typename T>
|
||||
void construct(T *ptr) {
|
||||
static_assert(sizeof(Concrete<T>) == sizeof(*base()),
|
||||
"ubi::Base specializations must be the same size as ubi::Base");
|
||||
Concrete<T>::construct(base(), ptr);
|
||||
}
|
||||
|
||||
typedef void (Node::* ConvertibleToBool)();
|
||||
void nonNull() {}
|
||||
|
||||
public:
|
||||
Node() { construct<void>(nullptr); }
|
||||
|
||||
template<typename T>
|
||||
Node(T *ptr) {
|
||||
construct(ptr);
|
||||
}
|
||||
template<typename T>
|
||||
Node &operator=(T *ptr) {
|
||||
construct(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// We can construct and assign from rooted forms of pointers.
|
||||
template<typename T>
|
||||
Node(const Rooted<T *> &root) {
|
||||
construct(root.get());
|
||||
}
|
||||
template<typename T>
|
||||
Node &operator=(const Rooted<T *> &root) {
|
||||
construct(root.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Constructors accepting SpiderMonkey's other generic-pointer-ish types.
|
||||
Node(JS::Value value);
|
||||
Node(JSGCTraceKind kind, void *ptr);
|
||||
|
||||
// copy construction and copy assignment just use memcpy, since we know
|
||||
// instances contain nothing but a vtable pointer and a data pointer.
|
||||
//
|
||||
// To be completely correct, concrete classes could provide a virtual
|
||||
// 'construct' member function, which we could invoke on rhs to construct an
|
||||
// instance in our storage. But this is good enough; there's no need to jump
|
||||
// through vtables for copying and assignment that are just going to move
|
||||
// two words around. The compiler knows how to optimize memcpy.
|
||||
Node(const Node &rhs) {
|
||||
memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u));
|
||||
}
|
||||
|
||||
Node &operator=(const Node &rhs) {
|
||||
memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Node &rhs) const { return *base() == *rhs.base(); }
|
||||
bool operator!=(const Node &rhs) const { return *base() != *rhs.base(); }
|
||||
|
||||
operator ConvertibleToBool() const {
|
||||
return base()->ptr ? &Node::nonNull : 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool is() const {
|
||||
return base()->typeName() == Concrete<T>::concreteTypeName;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *as() const {
|
||||
MOZ_ASSERT(is<T>());
|
||||
return static_cast<T *>(base()->ptr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *asOrNull() const {
|
||||
return is<T>() ? static_cast<T *>(base()->ptr) : nullptr;
|
||||
}
|
||||
|
||||
// If this node refers to something that can be represented as a
|
||||
// JavaScript value that is safe to expose to JavaScript code, return that
|
||||
// value. Otherwise return UndefinedValue(). JSStrings and some (but not
|
||||
// all!) JSObjects can be exposed.
|
||||
JS::Value exposeToJS() const;
|
||||
|
||||
const jschar *typeName() const { return base()->typeName(); }
|
||||
size_t size() const { return base()->size(); }
|
||||
EdgeRange *edges(JSContext *cx) const { return base()->edges(cx); }
|
||||
|
||||
// A hash policy for ubi::Nodes.
|
||||
// This simply uses the stock PointerHasher on the ubi::Node's pointer.
|
||||
// We specialize DefaultHasher below to make this the default.
|
||||
class HashPolicy {
|
||||
typedef js::PointerHasher<void *, mozilla::tl::FloorLog2<sizeof(void *)>::value> PtrHash;
|
||||
|
||||
public:
|
||||
typedef Node Lookup;
|
||||
|
||||
static js::HashNumber hash(const Lookup &l) { return PtrHash::hash(l.base()->ptr); }
|
||||
static bool match(const Node &k, const Lookup &l) { return k == l; }
|
||||
static void rekey(Node &k, const Node &newKey) { k = newKey; }
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Edge is the abstract base class representing an outgoing edge of a node.
|
||||
// Edges are owned by EdgeRanges, and need not have assignment operators or copy
|
||||
// constructors.
|
||||
//
|
||||
// Each Edge class should inherit from this base class, overriding as
|
||||
// appropriate.
|
||||
class Edge {
|
||||
protected:
|
||||
Edge() : name(nullptr), referent() { }
|
||||
virtual ~Edge() { }
|
||||
|
||||
public:
|
||||
// This edge's name.
|
||||
//
|
||||
// The storage is owned by this Edge, and will be freed when this Edge is
|
||||
// destructed.
|
||||
//
|
||||
// (In real life we'll want a better representation for names, to avoid
|
||||
// creating tons of strings when the names follow a pattern; and we'll need
|
||||
// to think about lifetimes carefully to ensure traversal stays cheap.)
|
||||
const jschar *name;
|
||||
|
||||
// This edge's referent.
|
||||
Node referent;
|
||||
|
||||
private:
|
||||
Edge(const Edge &) MOZ_DELETE;
|
||||
Edge &operator=(const Edge &) MOZ_DELETE;
|
||||
};
|
||||
|
||||
|
||||
// EdgeRange is an abstract base class for iterating over a node's outgoing
|
||||
// edges. (This is modeled after js::HashTable<K,V>::Range.)
|
||||
//
|
||||
// Concrete instances of this class need not be as lightweight as Node itself,
|
||||
// since they're usually only instantiated while iterating over a particular
|
||||
// object's edges. For example, a dumb implementation for JS Cells might use
|
||||
// JS_TraceChildren to to get the outgoing edges, and then store them in an
|
||||
// array internal to the EdgeRange.
|
||||
class EdgeRange {
|
||||
protected:
|
||||
// The current front edge of this range, or nullptr if this range is empty.
|
||||
Edge *front_;
|
||||
|
||||
EdgeRange() : front_(nullptr) { }
|
||||
|
||||
public:
|
||||
virtual ~EdgeRange() { };
|
||||
|
||||
// True if there are no more edges in this range.
|
||||
bool empty() const { return !front_; }
|
||||
|
||||
// The front edge of this range. This is owned by the EdgeRange, and is
|
||||
// only guaranteed to live until the next call to popFront, or until
|
||||
// the EdgeRange is destructed.
|
||||
const Edge &front() { return *front_; }
|
||||
|
||||
// Remove the front edge from this range. This should only be called if
|
||||
// !empty().
|
||||
virtual void popFront() = 0;
|
||||
|
||||
private:
|
||||
EdgeRange(const EdgeRange &) MOZ_DELETE;
|
||||
EdgeRange &operator=(const EdgeRange &) MOZ_DELETE;
|
||||
};
|
||||
|
||||
|
||||
// Concrete classes for ubi::Node referent types.
|
||||
|
||||
// A reusable ubi::Concrete specialization base class for types supported by
|
||||
// JS_TraceChildren.
|
||||
template<typename Referent>
|
||||
class TracerConcrete : public Base {
|
||||
const jschar *typeName() const MOZ_OVERRIDE { return concreteTypeName; }
|
||||
size_t size() const MOZ_OVERRIDE { return 0; } // not implemented yet; bug 1011300
|
||||
EdgeRange *edges(JSContext *) const MOZ_OVERRIDE;
|
||||
|
||||
TracerConcrete(Referent *ptr) : Base(ptr) { }
|
||||
|
||||
public:
|
||||
static const jschar concreteTypeName[];
|
||||
static void construct(void *storage, Referent *ptr) { new (storage) TracerConcrete(ptr); };
|
||||
};
|
||||
|
||||
template<> struct Concrete<JSObject> : TracerConcrete<JSObject> { };
|
||||
template<> struct Concrete<JSString> : TracerConcrete<JSString> { };
|
||||
template<> struct Concrete<JSScript> : TracerConcrete<JSScript> { };
|
||||
template<> struct Concrete<js::LazyScript> : TracerConcrete<js::LazyScript> { };
|
||||
template<> struct Concrete<js::jit::JitCode> : TracerConcrete<js::jit::JitCode> { };
|
||||
template<> struct Concrete<js::Shape> : TracerConcrete<js::Shape> { };
|
||||
template<> struct Concrete<js::BaseShape> : TracerConcrete<js::BaseShape> { };
|
||||
template<> struct Concrete<js::types::TypeObject> : TracerConcrete<js::types::TypeObject> { };
|
||||
|
||||
// The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts.
|
||||
template<>
|
||||
class Concrete<void> : public Base {
|
||||
const jschar *typeName() const MOZ_OVERRIDE;
|
||||
size_t size() const MOZ_OVERRIDE;
|
||||
EdgeRange *edges(JSContext *cx) const MOZ_OVERRIDE;
|
||||
|
||||
Concrete(void *ptr) : Base(ptr) { }
|
||||
|
||||
public:
|
||||
static void construct(void *storage, void *ptr) { new (storage) Concrete(ptr); }
|
||||
static const jschar concreteTypeName[];
|
||||
};
|
||||
|
||||
|
||||
} // namespace ubi
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
// Make ubi::Node::HashPolicy the default hash policy for ubi::Node.
|
||||
template<> struct DefaultHasher<JS::ubi::Node> : JS::ubi::Node::HashPolicy { };
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // js_UbiNode_h
|
|
@ -0,0 +1,208 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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 js_UbiNodeTraverse_h
|
||||
#define js_UbiNodeTraverse_h
|
||||
|
||||
#include "js/UbiNode.h"
|
||||
#include "js/Utility.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
namespace JS {
|
||||
namespace ubi {
|
||||
|
||||
// A breadth-first traversal template for graphs of ubi::Nodes.
|
||||
//
|
||||
// No GC may occur while an instance of this template is live.
|
||||
//
|
||||
// The provided Handler type should have two members:
|
||||
//
|
||||
// typename NodeData;
|
||||
//
|
||||
// The value type of |BreadthFirst<Handler>::visited|, the HashMap of
|
||||
// ubi::Nodes that have been visited so far. Since the algorithm needs a
|
||||
// hash table like this for its own use anyway, it is simple to let
|
||||
// Handler store its own metadata about each node in the same table.
|
||||
//
|
||||
// For example, if you want to find a shortest path to each node from any
|
||||
// traversal starting point, your |NodeData| type could record the first
|
||||
// edge to reach each node, and the node from which it originates. Then,
|
||||
// when the traversal is complete, you can walk backwards from any node
|
||||
// to some starting point, and the path recorded will be a shortest path.
|
||||
//
|
||||
// This type must have a default constructor. If this type owns any other
|
||||
// resources, move constructors and assignment operators are probably a
|
||||
// good idea, too.
|
||||
//
|
||||
// bool operator() (BreadthFirst &traversal,
|
||||
// Node origin, const Edge &edge,
|
||||
// Handler::NodeData *referentData, bool first);
|
||||
//
|
||||
// The visitor function, called to report that we have traversed
|
||||
// |edge| from |origin|. This is called once for each edge we traverse.
|
||||
// As this is a breadth-first search, any prior calls to the visitor function
|
||||
// were for origin nodes not further from the start nodes than |origin|.
|
||||
//
|
||||
// |traversal| is this traversal object, passed along for convenience.
|
||||
//
|
||||
// |referentData| is a pointer to the value of the entry in
|
||||
// |traversal.visited| for |edge.referent|; the visitor function can
|
||||
// store whatever metadata it likes about |edge.referent| there.
|
||||
//
|
||||
// |first| is true if this is the first time we have visited an edge
|
||||
// leading to |edge.referent|. This could be stored in NodeData, but
|
||||
// the algorithm knows whether it has just created the entry in
|
||||
// |traversal.visited|, so it passes it along for convenience.
|
||||
//
|
||||
// The visitor function may call |traversal.stop()| if it doesn't want
|
||||
// to visit any more nodes.
|
||||
//
|
||||
// The visitor function may consult |traversal.visited| for information
|
||||
// about other nodes, but it should not add or remove entries.
|
||||
//
|
||||
// The visitor function should return true on success, or false if an
|
||||
// error occurs. A false return value terminates the traversal
|
||||
// immediately, and causes BreadthFirst<Handler>::traverse to return
|
||||
// false.
|
||||
template<typename Handler>
|
||||
struct BreadthFirst {
|
||||
|
||||
// Construct a breadth-first traversal object that reports the nodes it
|
||||
// reaches to |handler|. The traversal object reports OOM on |cx|, and
|
||||
// asserts that no GC happens in |cx|'s runtime during its lifetime.
|
||||
//
|
||||
// We do nothing with noGC, other than require it to exist, with a lifetime
|
||||
// that encloses our own.
|
||||
BreadthFirst(JSContext *cx, Handler &handler, const JS::AutoCheckCannotGC &noGC)
|
||||
: cx(cx), visited(cx), handler(handler), pending(cx),
|
||||
traversalBegun(false), stopRequested(false)
|
||||
{ }
|
||||
|
||||
// Initialize this traversal object. Return false on OOM.
|
||||
bool init() { return visited.init(); }
|
||||
|
||||
// Add |node| as a starting point for the traversal. You may add
|
||||
// as many starting points as you like. Return false on OOM.
|
||||
bool addStart(Node node) { return pending.append(node); }
|
||||
|
||||
// Traverse the graph in breadth-first order, starting at the given
|
||||
// start nodes, applying |handler::operator()| for each edge traversed
|
||||
// as described above.
|
||||
//
|
||||
// This should be called only once per instance of this class.
|
||||
//
|
||||
// Return false on OOM or error return from |handler::operator()|.
|
||||
bool traverse()
|
||||
{
|
||||
MOZ_ASSERT(!traversalBegun);
|
||||
traversalBegun = true;
|
||||
|
||||
// While there are pending nodes, visit them, until we've found a path to the target.
|
||||
while (!pending.empty()) {
|
||||
Node origin = pending.front();
|
||||
pending.popFront();
|
||||
|
||||
// Get a range containing all origin's outgoing edges.
|
||||
js::ScopedJSDeletePtr<EdgeRange> range(origin.edges(cx));
|
||||
if (!range)
|
||||
return false;
|
||||
|
||||
// Traverse each edge.
|
||||
for (; !range->empty(); range->popFront()) {
|
||||
MOZ_ASSERT(!stopRequested);
|
||||
|
||||
const Edge &edge = range->front();
|
||||
typename NodeMap::AddPtr a = visited.lookupForAdd(edge.referent);
|
||||
bool first = !a;
|
||||
|
||||
if (first) {
|
||||
// This is the first time we've reached |edge.referent|.
|
||||
// Create an entry for it in |visited|, and arrange to
|
||||
// traverse its outgoing edges later.
|
||||
if (!visited.add(a, edge.referent, typename Handler::NodeData()) ||
|
||||
!pending.append(edge.referent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(a);
|
||||
|
||||
// Report this edge to the visitor function.
|
||||
if (!handler(*this, origin, edge, &a->value(), first))
|
||||
return false;
|
||||
|
||||
if (stopRequested)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Stop traversal, and return true from |traverse| without visiting any
|
||||
// more nodes. Only |handler::operator()| should call this function; it
|
||||
// may do so to stop the traversal early, without returning false and
|
||||
// then making |traverse|'s caller disambiguate that result from a real
|
||||
// error.
|
||||
void stop() { stopRequested = true; }
|
||||
|
||||
// The context with which we were constructed.
|
||||
JSContext *cx;
|
||||
|
||||
// A map associating each node N that we have reached with a
|
||||
// Handler::NodeData, for |handler|'s use. This is public, so that
|
||||
// |handler| can access it to see the traversal thus far.
|
||||
typedef js::HashMap<Node, typename Handler::NodeData> NodeMap;
|
||||
NodeMap visited;
|
||||
|
||||
private:
|
||||
// Our handler object.
|
||||
Handler &handler;
|
||||
|
||||
// A queue template. Appending and popping the front are constant time.
|
||||
// Wasted space is never more than some recent actual population plus the
|
||||
// current population.
|
||||
template <typename T>
|
||||
class Queue {
|
||||
js::Vector<T, 0> head, tail;
|
||||
size_t frontIndex;
|
||||
public:
|
||||
Queue(JSContext *cx) : head(cx), tail(cx), frontIndex(0) { }
|
||||
bool empty() { return frontIndex >= head.length(); }
|
||||
T &front() {
|
||||
MOZ_ASSERT(!empty());
|
||||
return head[frontIndex];
|
||||
}
|
||||
void popFront() {
|
||||
MOZ_ASSERT(!empty());
|
||||
frontIndex++;
|
||||
if (frontIndex >= head.length()) {
|
||||
head.clearAndFree();
|
||||
head.swap(tail);
|
||||
frontIndex = 0;
|
||||
}
|
||||
}
|
||||
bool append(const T &elt) {
|
||||
return frontIndex == 0 ? head.append(elt) : tail.append(elt);
|
||||
}
|
||||
};
|
||||
|
||||
// A queue of nodes that we have reached, but whose outgoing edges we
|
||||
// have not yet traversed. Nodes reachable in fewer edges are enqueued
|
||||
// earlier.
|
||||
Queue<Node> pending;
|
||||
|
||||
// True if our traverse function has been called.
|
||||
bool traversalBegun;
|
||||
|
||||
// True if we've been asked to stop the traversal.
|
||||
bool stopRequested;
|
||||
};
|
||||
|
||||
} // namespace ubi
|
||||
} // namespace JS
|
||||
|
||||
#endif // js_UbiNodeTraverse.h
|
|
@ -19,6 +19,7 @@
|
|||
#include "jstypes.h"
|
||||
|
||||
#include "js/Anchor.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/Utility.h"
|
||||
|
||||
|
@ -1288,6 +1289,13 @@ IsOptimizedPlaceholderMagicValue(const Value &v)
|
|||
return false;
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
ExposeValueToActiveJS(const Value &v)
|
||||
{
|
||||
if (v.isMarkable())
|
||||
ExposeGCThingToActiveJS(v.toGCThing(), v.gcKind());
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
static inline Value
|
||||
|
|
|
@ -10,10 +10,7 @@
|
|||
|
||||
#include "jscntxt.h"
|
||||
|
||||
#ifndef JS_YARR
|
||||
#include "irregexp/RegExpParser.h"
|
||||
#endif
|
||||
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
|
@ -94,28 +91,12 @@ js::CreateRegExpMatchResult(JSContext *cx, HandleString input, const MatchPairs
|
|||
static RegExpRunStatus
|
||||
ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re,
|
||||
HandleLinearString input, const jschar *chars, size_t length,
|
||||
size_t *lastIndex, MatchConduit &matches)
|
||||
size_t *lastIndex, MatchPairs &matches)
|
||||
{
|
||||
RegExpRunStatus status;
|
||||
|
||||
/* Switch between MatchOnly and IncludeSubpatterns modes. */
|
||||
if (matches.isPair) {
|
||||
#ifdef JS_YARR
|
||||
size_t lastIndex_orig = *lastIndex;
|
||||
/* Only one MatchPair slot provided: execute short-circuiting regexp. */
|
||||
status = re.executeMatchOnly(cx, chars, length, lastIndex, *matches.u.pair);
|
||||
if (status == RegExpRunStatus_Success && res)
|
||||
res->updateLazily(cx, input, &re, lastIndex_orig);
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
} else {
|
||||
/* Vector of MatchPairs provided: execute full regexp. */
|
||||
status = re.execute(cx, chars, length, lastIndex, *matches.u.pairs);
|
||||
if (status == RegExpRunStatus_Success && res) {
|
||||
if (!res->updateFromMatchPairs(cx, input, *matches.u.pairs))
|
||||
return RegExpRunStatus_Error;
|
||||
}
|
||||
RegExpRunStatus status = re.execute(cx, chars, length, lastIndex, matches);
|
||||
if (status == RegExpRunStatus_Success && res) {
|
||||
if (!res->updateFromMatchPairs(cx, input, matches))
|
||||
return RegExpRunStatus_Error;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
@ -131,10 +112,9 @@ js::ExecuteRegExpLegacy(JSContext *cx, RegExpStatics *res, RegExpObject &reobj,
|
|||
return false;
|
||||
|
||||
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||
MatchConduit conduit(&matches);
|
||||
|
||||
RegExpRunStatus status =
|
||||
ExecuteRegExpImpl(cx, res, *shared, input_, chars, length, lastIndex, conduit);
|
||||
ExecuteRegExpImpl(cx, res, *shared, input_, chars, length, lastIndex, matches);
|
||||
|
||||
if (status == RegExpRunStatus_Error)
|
||||
return false;
|
||||
|
@ -308,16 +288,11 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
|
|||
if (!escapedSourceStr)
|
||||
return false;
|
||||
|
||||
#ifdef JS_YARR
|
||||
if (!RegExpShared::checkSyntax(cx, nullptr, escapedSourceStr))
|
||||
return false;
|
||||
#else // JS_YARR
|
||||
CompileOptions options(cx);
|
||||
frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
|
||||
|
||||
if (!irregexp::ParsePatternSyntax(dummyTokenStream, cx->tempLifoAlloc(), escapedSourceStr))
|
||||
return false;
|
||||
#endif // JS_YARR
|
||||
|
||||
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
|
||||
if (!res)
|
||||
|
@ -557,7 +532,7 @@ js_InitRegExpClass(JSContext *cx, HandleObject obj)
|
|||
|
||||
RegExpRunStatus
|
||||
js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string,
|
||||
MatchConduit &matches, RegExpStaticsUpdate staticsUpdate)
|
||||
MatchPairs &matches, RegExpStaticsUpdate staticsUpdate)
|
||||
{
|
||||
/* Step 1 (b) was performed by CallNonGenericMethod. */
|
||||
Rooted<RegExpObject*> reobj(cx, ®exp->as<RegExpObject>());
|
||||
|
@ -633,7 +608,7 @@ js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string,
|
|||
|
||||
/* ES5 15.10.6.2 (and 15.10.6.3, which calls 15.10.6.2). */
|
||||
static RegExpRunStatus
|
||||
ExecuteRegExp(JSContext *cx, CallArgs args, MatchConduit &matches)
|
||||
ExecuteRegExp(JSContext *cx, CallArgs args, MatchPairs &matches)
|
||||
{
|
||||
/* Step 1 (a) was performed by CallNonGenericMethod. */
|
||||
RootedObject regexp(cx, &args.thisv().toObject());
|
||||
|
@ -653,9 +628,8 @@ regexp_exec_impl(JSContext *cx, HandleObject regexp, HandleString string,
|
|||
{
|
||||
/* Execute regular expression and gather matches. */
|
||||
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||
MatchConduit conduit(&matches);
|
||||
|
||||
RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, conduit, staticsUpdate);
|
||||
RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, matches, staticsUpdate);
|
||||
|
||||
if (status == RegExpRunStatus_Error)
|
||||
return false;
|
||||
|
@ -711,14 +685,8 @@ js::regexp_exec_no_statics(JSContext *cx, unsigned argc, Value *vp)
|
|||
static bool
|
||||
regexp_test_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
#ifdef JS_YARR
|
||||
MatchPair match;
|
||||
MatchConduit conduit(&match);
|
||||
#else
|
||||
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||
MatchConduit conduit(&matches);
|
||||
#endif
|
||||
RegExpRunStatus status = ExecuteRegExp(cx, args, conduit);
|
||||
RegExpRunStatus status = ExecuteRegExp(cx, args, matches);
|
||||
args.rval().setBoolean(status == RegExpRunStatus_Success);
|
||||
return status != RegExpRunStatus_Error;
|
||||
}
|
||||
|
@ -727,14 +695,8 @@ regexp_test_impl(JSContext *cx, CallArgs args)
|
|||
bool
|
||||
js::regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, bool *result)
|
||||
{
|
||||
#ifdef JS_YARR
|
||||
MatchPair match;
|
||||
MatchConduit conduit(&match);
|
||||
#else
|
||||
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||
MatchConduit conduit(&matches);
|
||||
#endif
|
||||
RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, conduit, UpdateRegExpStatics);
|
||||
RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, matches, UpdateRegExpStatics);
|
||||
*result = (status == RegExpRunStatus_Success);
|
||||
return status != RegExpRunStatus_Error;
|
||||
}
|
||||
|
@ -757,14 +719,8 @@ js::regexp_test_no_statics(JSContext *cx, unsigned argc, Value *vp)
|
|||
RootedObject regexp(cx, &args[0].toObject());
|
||||
RootedString string(cx, args[1].toString());
|
||||
|
||||
#ifdef JS_YARR
|
||||
MatchPair match;
|
||||
MatchConduit conduit(&match);
|
||||
#else
|
||||
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||
MatchConduit conduit(&matches);
|
||||
#endif
|
||||
RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, conduit, DontUpdateRegExpStatics);
|
||||
RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, matches, DontUpdateRegExpStatics);
|
||||
args.rval().setBoolean(status == RegExpRunStatus_Success);
|
||||
return status != RegExpRunStatus_Error;
|
||||
}
|
||||
|
|
|
@ -19,15 +19,13 @@ js_InitRegExpClass(JSContext *cx, js::HandleObject obj);
|
|||
|
||||
namespace js {
|
||||
|
||||
class MatchConduit;
|
||||
|
||||
// Whether RegExp statics should be updated with the input and results of a
|
||||
// regular expression execution.
|
||||
enum RegExpStaticsUpdate { UpdateRegExpStatics, DontUpdateRegExpStatics };
|
||||
|
||||
RegExpRunStatus
|
||||
ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string,
|
||||
MatchConduit &matches, RegExpStaticsUpdate staticsUpdate);
|
||||
MatchPairs &matches, RegExpStaticsUpdate staticsUpdate);
|
||||
|
||||
/*
|
||||
* Legacy behavior of ExecuteRegExp(), which is baked into the JSAPI.
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
#include "builtin/TestingFunctions.h"
|
||||
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/Scoped.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
@ -18,7 +21,11 @@
|
|||
|
||||
#include "jit/AsmJS.h"
|
||||
#include "jit/AsmJSLink.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "js/UbiNode.h"
|
||||
#include "js/UbiNodeTraverse.h"
|
||||
#include "js/Vector.h"
|
||||
#include "vm/ForkJoin.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
|
@ -33,6 +40,8 @@ using namespace js;
|
|||
using namespace JS;
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::Move;
|
||||
using mozilla::ScopedFreePtr;
|
||||
|
||||
// If fuzzingSafe is set, remove functionality that could cause problems with
|
||||
// fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE.
|
||||
|
@ -1651,6 +1660,214 @@ ReportLargeAllocationFailure(JSContext *cx, unsigned argc, jsval *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
namespace heaptools {
|
||||
|
||||
// An edge to a node from its predecessor in a path through the graph.
|
||||
class BackEdge {
|
||||
// The node from which this edge starts.
|
||||
JS::ubi::Node predecessor_;
|
||||
|
||||
// The name of this edge. We own this storage.
|
||||
ScopedFreePtr<jschar> name_;
|
||||
|
||||
public:
|
||||
BackEdge() : name_(nullptr) { }
|
||||
// Construct an initialized back edge. Take ownership of |name|.
|
||||
BackEdge(JS::ubi::Node predecessor, jschar *name)
|
||||
: predecessor_(predecessor), name_(name) { }
|
||||
BackEdge(BackEdge &&rhs) : predecessor_(rhs.predecessor_), name_(rhs.name_.forget()) { }
|
||||
BackEdge &operator=(BackEdge &&rhs) {
|
||||
MOZ_ASSERT(&rhs != this);
|
||||
this->~BackEdge();
|
||||
new(this) BackEdge(Move(rhs));
|
||||
return *this;
|
||||
}
|
||||
|
||||
jschar *forgetName() { return name_.forget(); }
|
||||
JS::ubi::Node predecessor() const { return predecessor_; }
|
||||
|
||||
private:
|
||||
// No copy constructor or copying assignment.
|
||||
BackEdge(const BackEdge &) MOZ_DELETE;
|
||||
BackEdge &operator=(const BackEdge &) MOZ_DELETE;
|
||||
};
|
||||
|
||||
// A path-finding handler class for use with JS::ubi::BreadthFirst.
|
||||
struct FindPathHandler {
|
||||
typedef BackEdge NodeData;
|
||||
typedef JS::ubi::BreadthFirst<FindPathHandler> Traversal;
|
||||
|
||||
FindPathHandler(JS::ubi::Node start, JS::ubi::Node target,
|
||||
AutoValueVector &nodes, Vector<ScopedFreePtr<jschar> > &edges)
|
||||
: start(start), target(target), foundPath(false),
|
||||
nodes(nodes), edges(edges) { }
|
||||
|
||||
bool
|
||||
operator()(Traversal &traversal, JS::ubi::Node origin, const JS::ubi::Edge &edge,
|
||||
BackEdge *backEdge, bool first)
|
||||
{
|
||||
// We take care of each node the first time we visit it, so there's
|
||||
// nothing to be done on subsequent visits.
|
||||
if (!first)
|
||||
return true;
|
||||
|
||||
// Record how we reached this node. This is the last edge on a
|
||||
// shortest path to this node.
|
||||
jschar *edgeName = js_strdup(traversal.cx, edge.name);
|
||||
if (!edgeName)
|
||||
return false;
|
||||
*backEdge = mozilla::Move(BackEdge(origin, edgeName));
|
||||
|
||||
// Have we reached our final target node?
|
||||
if (edge.referent == target) {
|
||||
// Record the path that got us here, which must be a shortest path.
|
||||
if (!recordPath(traversal))
|
||||
return false;
|
||||
foundPath = true;
|
||||
traversal.stop();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// We've found a path to our target. Walk the backlinks to produce the
|
||||
// (reversed) path, saving the path in |nodes| and |edges|. |nodes| is
|
||||
// rooted, so it can hold the path's nodes as we leave the scope of
|
||||
// the AutoCheckCannotGC.
|
||||
bool recordPath(Traversal &traversal) {
|
||||
JS::ubi::Node here = target;
|
||||
|
||||
do {
|
||||
Traversal::NodeMap::Ptr p = traversal.visited.lookup(here);
|
||||
MOZ_ASSERT(p);
|
||||
JS::ubi::Node predecessor = p->value().predecessor();
|
||||
if (!nodes.append(predecessor.exposeToJS()) ||
|
||||
!edges.append(p->value().forgetName()))
|
||||
return false;
|
||||
here = predecessor;
|
||||
} while (here != start);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// The node we're starting from.
|
||||
JS::ubi::Node start;
|
||||
|
||||
// The node we're looking for.
|
||||
JS::ubi::Node target;
|
||||
|
||||
// True if we found a path to target, false if we didn't.
|
||||
bool foundPath;
|
||||
|
||||
// The nodes and edges of the path --- should we find one. The path is
|
||||
// stored in reverse order, because that's how it's easiest for us to
|
||||
// construct it:
|
||||
// - edges[i] is the name of the edge from nodes[i] to nodes[i-1].
|
||||
// - edges[0] is the name of the edge from nodes[0] to the target.
|
||||
// - The last node, nodes[n-1], is the start node.
|
||||
AutoValueVector &nodes;
|
||||
Vector<ScopedFreePtr<jschar> > &edges;
|
||||
};
|
||||
|
||||
} // namespace heaptools
|
||||
|
||||
static bool
|
||||
FindPath(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (argc < 2) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
|
||||
"findPath", "1", "");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't ToString non-objects given as 'start' or 'target'. We can't
|
||||
// see edges to non-string primitive values, and it doesn't make much
|
||||
// sense to ask for paths to or from a freshly allocated string, so
|
||||
// if a non-string primitive appears here it's probably a mistake.
|
||||
if (!args[0].isObject() && !args[0].isString()) {
|
||||
js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
|
||||
JSDVG_SEARCH_STACK, args[0], JS::NullPtr(),
|
||||
"neither an object nor a string", NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[1].isObject() && !args[1].isString()) {
|
||||
js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
|
||||
JSDVG_SEARCH_STACK, args[0], JS::NullPtr(),
|
||||
"neither an object nor a string", NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoValueVector nodes(cx);
|
||||
Vector<ScopedFreePtr<jschar> > edges(cx);
|
||||
|
||||
{
|
||||
// We can't tolerate the GC moving things around while we're searching
|
||||
// the heap. Check that nothing we do causes a GC.
|
||||
JS::AutoCheckCannotGC autoCannotGC;
|
||||
|
||||
JS::ubi::Node start(args[0]), target(args[1]);
|
||||
|
||||
heaptools::FindPathHandler handler(start, target, nodes, edges);
|
||||
heaptools::FindPathHandler::Traversal traversal(cx, handler, autoCannotGC);
|
||||
if (!traversal.init() || !traversal.addStart(start))
|
||||
return false;
|
||||
|
||||
if (!traversal.traverse())
|
||||
return false;
|
||||
|
||||
if (!handler.foundPath) {
|
||||
// We didn't find any paths from the start to the target.
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// |nodes| and |edges| contain the path from |start| to |target|, reversed.
|
||||
// Construct a JavaScript array describing the path from the start to the
|
||||
// target. Each element has the form:
|
||||
//
|
||||
// { node: <object or string>, edge: <string describing outgoing edge from node> }
|
||||
//
|
||||
// or, if the node is some internal thing, that isn't a proper
|
||||
// JavaScript value:
|
||||
//
|
||||
// { node: undefined, edge: <string> }
|
||||
size_t length = nodes.length();
|
||||
RootedObject result(cx, NewDenseAllocatedArray(cx, length));
|
||||
if (!result)
|
||||
return false;
|
||||
result->ensureDenseInitializedLength(cx, 0, length);
|
||||
|
||||
// Walk |nodes| and |edges| in the stored order, and construct the result
|
||||
// array in start-to-target order.
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
// Build an object describing the node and edge.
|
||||
RootedObject obj(cx, NewBuiltinClassInstance<JSObject>(cx));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (!JS_DefineProperty(cx, obj, "node", nodes[i],
|
||||
JSPROP_ENUMERATE, nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
RootedString edge(cx, js_NewString<CanGC>(cx, edges[i].get(), js_strlen(edges[i])));
|
||||
if (!edge)
|
||||
return false;
|
||||
edges[i].forget();
|
||||
RootedValue edgeString(cx, StringValue(edge));
|
||||
if (!JS_DefineProperty(cx, obj, "edge", edgeString,
|
||||
JSPROP_ENUMERATE, nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
result->setDenseElement(length - i - 1, ObjectValue(*obj));
|
||||
}
|
||||
|
||||
args.rval().setObject(*result);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const JSFunctionSpecWithHelp TestingFunctions[] = {
|
||||
JS_FN_HELP("gc", ::GC, 0, 0,
|
||||
"gc([obj] | 'compartment')",
|
||||
|
@ -1931,6 +2148,19 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
|
|||
" then return undefined. In Gecko, this sends a memory pressure notification, which\n"
|
||||
" can free up some memory."),
|
||||
|
||||
JS_FN_HELP("findPath", FindPath, 2, 0,
|
||||
"findPath(start, target)",
|
||||
" Return an array describing one of the shortest paths of GC heap edges from\n"
|
||||
" |start| to |target|, or |undefined| if |target| is unreachable from |start|.\n"
|
||||
" Each element of the array is either of the form:\n"
|
||||
" { node: <object or string>, edge: <string describing edge from node> }\n"
|
||||
" if the node is a JavaScript object or value; or of the form:\n"
|
||||
" { type: <string describing node>, edge: <string describing edge> }\n"
|
||||
" if the node is some internal thing that is not a proper JavaScript value\n"
|
||||
" (like a shape or a scope chain element). The destination of the i'th array\n"
|
||||
" element's edge is the node of the i+1'th array element; the destination of\n"
|
||||
" the last array element is implicitly |target|.\n"),
|
||||
|
||||
#ifdef DEBUG
|
||||
JS_FN_HELP("dumpObject", DumpObject, 1, 0,
|
||||
"dumpObject()",
|
||||
|
|
|
@ -3004,20 +3004,6 @@ if test "$ENABLE_TRACE_LOGGING"; then
|
|||
AC_DEFINE(JS_TRACE_LOGGING)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable yarr regexp engine
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(yarr,
|
||||
[ --enable-yarr Enable yarr regexp engine],
|
||||
ENABLE_YARR=1,
|
||||
ENABLE_YARR= )
|
||||
|
||||
AC_SUBST(ENABLE_YARR)
|
||||
|
||||
if test "$ENABLE_YARR"; then
|
||||
AC_DEFINE(JS_YARR)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable any treating of compile warnings as errors
|
||||
dnl ========================================================
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
load(libdir + "match.js")
|
||||
|
||||
// At the moment, findPath just returns the names as provided by ubi::Node,
|
||||
// which just uses JS_TraceChildren for now. However, we have various plans
|
||||
// to improve the quality of ubi::Node's metadata, to improve the precision
|
||||
// and clarity of the results here.
|
||||
|
||||
var o = { w: { x: { y: { z: {} } } } };
|
||||
Match.Pattern([{node: {}, edge: "w"},
|
||||
{node: {}, edge: "x"},
|
||||
{node: {}, edge: "y"},
|
||||
{node: {}, edge: "z"}])
|
||||
.assert(findPath(o, o.w.x.y.z));
|
||||
print(uneval(findPath(o, o.w.x.y.z)));
|
||||
|
||||
var a = [ , o ];
|
||||
Match.Pattern([{node: {}, edge: "objectElements[1]"}])
|
||||
.assert(findPath(a, o));
|
||||
print(uneval(findPath(a, o)));
|
||||
|
||||
function C() {}
|
||||
C.prototype.obj = {};
|
||||
var c = new C;
|
||||
Match.Pattern([{node: {}, edge: "type"},
|
||||
{node: Match.Pattern.ANY, edge: "type_proto"},
|
||||
{node: { constructor: Match.Pattern.ANY }, edge: "obj"}])
|
||||
.assert(findPath(c, c.obj));
|
||||
print(uneval(findPath(c, c.obj)));
|
||||
|
||||
function f(x) { return function g(y) { return x+y; }; }
|
||||
var o = {}
|
||||
var gc = f(o);
|
||||
Match.Pattern([{node: gc, edge: "fun_callscope"},
|
||||
{node: Match.Pattern.ANY, edge: "x"}])
|
||||
.assert(findPath(gc, o));
|
||||
print(uneval(findPath(gc, o)));
|
||||
|
||||
Match.Pattern([{node: {}, edge: "shape"},
|
||||
{node: Match.Pattern.ANY, edge: "base"},
|
||||
{node: Match.Pattern.ANY, edge: "parent"},
|
||||
{node: {}, edge: "o"}])
|
||||
.assert(findPath(o, o));
|
||||
print(findPath(o, o).map((e) => e.edge).toString());
|
||||
|
|
@ -21,21 +21,9 @@
|
|||
(js::jit::Simulator::Current()->call( \
|
||||
JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 8, p0, p1, p2, p3, p4, p5, p6, p7) & 0xffffffff)
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
#define CALL_GENERATED_YARR_CODE3(entry, p0, p1, p2) \
|
||||
js::jit::Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 3, p0, p1, p2)
|
||||
|
||||
#define CALL_GENERATED_YARR_CODE4(entry, p0, p1, p2, p3) \
|
||||
js::jit::Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 4, p0, p1, p2, p3)
|
||||
|
||||
#else // JS_YARR
|
||||
|
||||
#define CALL_GENERATED_REGEXP(entry, p0) \
|
||||
js::jit::Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 1, p0)
|
||||
|
||||
#endif // JS_YARR
|
||||
|
||||
#define CALL_GENERATED_ASMJS(entry, p0, p1) \
|
||||
(Simulator::Current()->call(JS_FUNC_TO_DATA_PTR(uint8_t *, entry), 2, p0, p1) & 0xffffffff)
|
||||
|
||||
|
@ -45,21 +33,9 @@
|
|||
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
|
||||
entry(p0, p1, p2, p3, p4, p5, p6, p7)
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
#define CALL_GENERATED_YARR_CODE3(entry, p0, p1, p2) \
|
||||
entry(p0, p1, p2)
|
||||
|
||||
#define CALL_GENERATED_YARR_CODE4(entry, p0, p1, p2, p3) \
|
||||
entry(p0, p1, p2, p3)
|
||||
|
||||
#else // JS_YARR
|
||||
|
||||
#define CALL_GENERATED_REGEXP(entry, p0) \
|
||||
entry(p0)
|
||||
|
||||
#endif // JS_YARR
|
||||
|
||||
#define CALL_GENERATED_ASMJS(entry, p0, p1) \
|
||||
entry(p0, p1)
|
||||
|
||||
|
|
|
@ -541,9 +541,6 @@ Assembler::finish()
|
|||
JS_ASSERT(!isFinished);
|
||||
isFinished = true;
|
||||
|
||||
for (size_t i = 0; i < jumps_.length(); i++)
|
||||
jumps_[i].fixOffset(m_buffer);
|
||||
|
||||
for (unsigned int i = 0; i < tmpDataRelocations_.length(); i++) {
|
||||
int offset = tmpDataRelocations_[i].getOffset();
|
||||
int real_offset = offset + m_buffer.poolSizeBefore(offset);
|
||||
|
|
|
@ -1242,18 +1242,10 @@ class Assembler : public AssemblerShared
|
|||
// gets moved (executable copy, gc, etc.)
|
||||
struct RelativePatch
|
||||
{
|
||||
// the offset within the code buffer where the value is loaded that
|
||||
// we want to fix-up
|
||||
BufferOffset offset;
|
||||
void *target;
|
||||
Relocation::Kind kind;
|
||||
void fixOffset(ARMBuffer &m_buffer) {
|
||||
offset = BufferOffset(offset.getOffset() + m_buffer.poolSizeBefore(offset.getOffset()));
|
||||
}
|
||||
RelativePatch(BufferOffset offset, void *target, Relocation::Kind kind)
|
||||
: offset(offset),
|
||||
target(target),
|
||||
kind(kind)
|
||||
RelativePatch(void *target, Relocation::Kind kind)
|
||||
: target(target), kind(kind)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -1652,7 +1644,7 @@ class Assembler : public AssemblerShared
|
|||
|
||||
protected:
|
||||
void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) {
|
||||
enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind));
|
||||
enoughMemory_ &= jumps_.append(RelativePatch(target.value, kind));
|
||||
if (kind == Relocation::JITCODE)
|
||||
writeRelocation(src);
|
||||
}
|
||||
|
|
|
@ -1109,7 +1109,7 @@ Simulator::FlushICache(void *start_addr, size_t size)
|
|||
IonSpewCont(IonSpew_CacheFlush, "[%p %zx]", start_addr, size);
|
||||
if (!Simulator::ICacheCheckingEnabled)
|
||||
return;
|
||||
SimulatorRuntime *srt = Simulator::Current()->srt_;
|
||||
SimulatorRuntime *srt = TlsPerThreadData.get()->simulatorRuntime();
|
||||
AutoLockSimulatorRuntime alsr(srt);
|
||||
js::jit::FlushICache(srt->icache(), start_addr, size);
|
||||
}
|
||||
|
@ -1188,14 +1188,12 @@ class Redirection
|
|||
{
|
||||
friend class SimulatorRuntime;
|
||||
|
||||
Redirection(void *nativeFunction, ABIFunctionType type)
|
||||
Redirection(void *nativeFunction, ABIFunctionType type, SimulatorRuntime *srt)
|
||||
: nativeFunction_(nativeFunction),
|
||||
swiInstruction_(Assembler::AL | (0xf * (1 << 24)) | kCallRtRedirected),
|
||||
type_(type),
|
||||
next_(nullptr)
|
||||
{
|
||||
Simulator *sim = Simulator::Current();
|
||||
SimulatorRuntime *srt = sim->srt_;
|
||||
next_ = srt->redirection();
|
||||
if (Simulator::ICacheCheckingEnabled)
|
||||
FlushICache(srt->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
|
||||
|
@ -1208,10 +1206,13 @@ class Redirection
|
|||
ABIFunctionType type() const { return type_; }
|
||||
|
||||
static Redirection *Get(void *nativeFunction, ABIFunctionType type) {
|
||||
Simulator *sim = Simulator::Current();
|
||||
AutoLockSimulatorRuntime alsr(sim->srt_);
|
||||
PerThreadData *pt = TlsPerThreadData.get();
|
||||
SimulatorRuntime *srt = pt->simulatorRuntime();
|
||||
AutoLockSimulatorRuntime alsr(srt);
|
||||
|
||||
Redirection *current = sim->srt_->redirection();
|
||||
JS_ASSERT_IF(pt->simulator(), pt->simulator()->srt_ == srt);
|
||||
|
||||
Redirection *current = srt->redirection();
|
||||
for (; current != nullptr; current = current->next_) {
|
||||
if (current->nativeFunction_ == nativeFunction) {
|
||||
MOZ_ASSERT(current->type() == type);
|
||||
|
@ -1225,7 +1226,7 @@ class Redirection
|
|||
__FILE__, __LINE__);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
new(redir) Redirection(nativeFunction, type);
|
||||
new(redir) Redirection(nativeFunction, type, srt);
|
||||
return redir;
|
||||
}
|
||||
|
||||
|
|
|
@ -1278,7 +1278,7 @@ SimulatorRuntime::ICacheHasher::match(const Key &k, const Lookup &l)
|
|||
void
|
||||
Simulator::FlushICache(void *start_addr, size_t size)
|
||||
{
|
||||
SimulatorRuntime *srt = Simulator::Current()->srt_;
|
||||
SimulatorRuntime *srt = TlsPerThreadData.get()->simulatorRuntime();
|
||||
AutoLockSimulatorRuntime alsr(srt);
|
||||
js::jit::FlushICache(srt->icache(), start_addr, size);
|
||||
}
|
||||
|
@ -1345,14 +1345,12 @@ class Redirection
|
|||
{
|
||||
friend class SimulatorRuntime;
|
||||
|
||||
Redirection(void* nativeFunction, ABIFunctionType type)
|
||||
Redirection(void* nativeFunction, ABIFunctionType type, SimulatorRuntime *srt)
|
||||
: nativeFunction_(nativeFunction),
|
||||
swiInstruction_(kCallRedirInstr),
|
||||
type_(type),
|
||||
next_(nullptr)
|
||||
{
|
||||
Simulator *sim = Simulator::Current();
|
||||
SimulatorRuntime *srt = sim->srt_;
|
||||
next_ = srt->redirection();
|
||||
if (Simulator::ICacheCheckingEnabled)
|
||||
FlushICache(srt->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
|
||||
|
@ -1365,10 +1363,13 @@ class Redirection
|
|||
ABIFunctionType type() const { return type_; }
|
||||
|
||||
static Redirection *Get(void *nativeFunction, ABIFunctionType type) {
|
||||
Simulator *sim = Simulator::Current();
|
||||
AutoLockSimulatorRuntime alsr(sim->srt_);
|
||||
PerThreadData *pt = TlsPerThreadData.get();
|
||||
SimulatorRuntime *srt = pt->simulatorRuntime();
|
||||
AutoLockSimulatorRuntime alsr(srt);
|
||||
|
||||
Redirection *current = sim->srt_->redirection();
|
||||
JS_ASSERT_IF(pt->simulator(), pt->simulator()->srt_ == srt);
|
||||
|
||||
Redirection *current = srt->redirection();
|
||||
for (; current != nullptr; current = current->next_) {
|
||||
if (current->nativeFunction_ == nativeFunction) {
|
||||
MOZ_ASSERT(current->type() == type);
|
||||
|
@ -1382,7 +1383,7 @@ class Redirection
|
|||
__FILE__, __LINE__);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
new(redir) Redirection(nativeFunction, type);
|
||||
new(redir) Redirection(nativeFunction, type, srt);
|
||||
return redir;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ PreWrap(JSContext *cx, JS::HandleObject scope, JS::HandleObject obj, unsigned fl
|
|||
|
||||
static JSObject *
|
||||
Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj,
|
||||
JS::HandleObject proto, JS::HandleObject parent, unsigned flags)
|
||||
JS::HandleObject parent, unsigned flags)
|
||||
{
|
||||
return js::Wrapper::New(cx, obj, parent, &js::CrossCompartmentWrapper::singleton);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "js/StructuredClone.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/UbiNode.h"
|
||||
#include "js/Utility.h"
|
||||
#include "js/Value.h"
|
||||
#include "js/Vector.h"
|
||||
|
|
|
@ -758,8 +758,7 @@ typedef bool
|
|||
*/
|
||||
typedef JSObject *
|
||||
(* JSWrapObjectCallback)(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj,
|
||||
JS::HandleObject proto, JS::HandleObject parent,
|
||||
unsigned flags);
|
||||
JS::HandleObject parent, unsigned flags);
|
||||
|
||||
/*
|
||||
* Callback used by the wrap hook to ask the embedding to prepare an object
|
||||
|
|
|
@ -402,7 +402,6 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin
|
|||
return true;
|
||||
}
|
||||
|
||||
RootedObject proto(cx, TaggedProto::LazyProto);
|
||||
RootedObject existing(cx, existingArg);
|
||||
if (existing) {
|
||||
// Is it possible to reuse |existing|?
|
||||
|
@ -416,7 +415,7 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin
|
|||
}
|
||||
}
|
||||
|
||||
obj.set(cb->wrap(cx, existing, obj, proto, global, flags));
|
||||
obj.set(cb->wrap(cx, existing, obj, global, flags));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -2254,11 +2254,7 @@ DoMatchGlobal(JSContext *cx, CallArgs args, RegExpStatics *res, HandleLinearStri
|
|||
// techniques from the spec to implement step 8f's loop.
|
||||
|
||||
// Step 8f.
|
||||
#ifdef JS_YARR
|
||||
MatchPair match;
|
||||
#else
|
||||
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||
#endif
|
||||
size_t charsLen = input->length();
|
||||
const jschar *chars = input->chars();
|
||||
RegExpShared &re = g.regExp();
|
||||
|
@ -2268,11 +2264,7 @@ DoMatchGlobal(JSContext *cx, CallArgs args, RegExpStatics *res, HandleLinearStri
|
|||
|
||||
// Steps 8f(i-ii), minus "lastIndex" updates (see above).
|
||||
size_t nextSearchIndex = searchIndex;
|
||||
#ifdef JS_YARR
|
||||
RegExpRunStatus status = re.executeMatchOnly(cx, chars, charsLen, &nextSearchIndex, match);
|
||||
#else
|
||||
RegExpRunStatus status = re.execute(cx, chars, charsLen, &nextSearchIndex, matches);
|
||||
#endif
|
||||
if (status == RegExpRunStatus_Error)
|
||||
return false;
|
||||
|
||||
|
@ -2281,10 +2273,7 @@ DoMatchGlobal(JSContext *cx, CallArgs args, RegExpStatics *res, HandleLinearStri
|
|||
break;
|
||||
|
||||
lastSuccessfulStart = searchIndex;
|
||||
|
||||
#ifndef JS_YARR
|
||||
MatchPair &match = matches[0];
|
||||
#endif
|
||||
|
||||
// Steps 8f(iii)(1-3).
|
||||
searchIndex = match.isEmpty() ? nextSearchIndex + 1 : nextSearchIndex;
|
||||
|
@ -2423,25 +2412,15 @@ js::str_search(JSContext *cx, unsigned argc, Value *vp)
|
|||
|
||||
/* Per ECMAv5 15.5.4.12 (5) The last index property is ignored and left unchanged. */
|
||||
size_t i = 0;
|
||||
#ifdef JS_YARR
|
||||
MatchPair match;
|
||||
RegExpRunStatus status = g.regExp().executeMatchOnly(cx, chars, length, &i, match);
|
||||
#else
|
||||
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||
RegExpRunStatus status = g.regExp().execute(cx, chars, length, &i, matches);
|
||||
#endif
|
||||
if (status == RegExpRunStatus_Error)
|
||||
return false;
|
||||
|
||||
if (status == RegExpRunStatus_Success)
|
||||
res->updateLazily(cx, linearStr, &g.regExp(), 0);
|
||||
|
||||
#ifdef JS_YARR
|
||||
JS_ASSERT_IF(status == RegExpRunStatus_Success_NotFound, match.start == -1);
|
||||
args.rval().setInt32(match.start);
|
||||
#else
|
||||
args.rval().setInt32(status == RegExpRunStatus_Success_NotFound ? -1 : matches[0].start);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3100,11 +3079,7 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl
|
|||
|
||||
size_t charsLen = flatStr->length();
|
||||
|
||||
#ifdef JS_YARR
|
||||
MatchPair match;
|
||||
#else
|
||||
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||
#endif
|
||||
size_t startIndex = 0; /* Index used for iterating through the string. */
|
||||
size_t lastIndex = 0; /* Index after last successful match. */
|
||||
size_t lazyIndex = 0; /* Index before last successful match. */
|
||||
|
@ -3114,19 +3089,12 @@ StrReplaceRegexpRemove(JSContext *cx, HandleString str, RegExpShared &re, Mutabl
|
|||
if (!CheckForInterrupt(cx))
|
||||
return false;
|
||||
|
||||
#ifdef JS_YARR
|
||||
RegExpRunStatus status = re.executeMatchOnly(cx, flatStr->chars(), charsLen, &startIndex, match);
|
||||
#else
|
||||
RegExpRunStatus status = re.execute(cx, flatStr->chars(), charsLen, &startIndex, matches);
|
||||
#endif
|
||||
if (status == RegExpRunStatus_Error)
|
||||
return false;
|
||||
if (status == RegExpRunStatus_Success_NotFound)
|
||||
break;
|
||||
|
||||
#ifndef JS_YARR
|
||||
MatchPair &match = matches[0];
|
||||
#endif
|
||||
|
||||
/* Include the latest unmatched substring. */
|
||||
if (size_t(match.start) > lastIndex) {
|
||||
|
|
|
@ -145,12 +145,10 @@ JSObject *Wrapper::defaultProto = TaggedProto::LazyProto;
|
|||
|
||||
extern JSObject *
|
||||
js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
|
||||
HandleObject wrappedProto, HandleObject parent,
|
||||
unsigned flags)
|
||||
HandleObject parent, unsigned flags)
|
||||
{
|
||||
// Allow wrapping outer window proxies.
|
||||
JS_ASSERT(!obj->is<WrapperObject>() || obj->getClass()->ext.innerObject);
|
||||
JS_ASSERT(wrappedProto == TaggedProto::LazyProto);
|
||||
return Wrapper::New(cx, obj, parent, &CrossCompartmentWrapper::singleton);
|
||||
}
|
||||
|
||||
|
|
|
@ -245,8 +245,7 @@ class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
|
|||
|
||||
extern JSObject *
|
||||
TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
|
||||
HandleObject wrappedProto, HandleObject parent,
|
||||
unsigned flags);
|
||||
HandleObject parent, unsigned flags);
|
||||
|
||||
// Proxy family for wrappers. Public so that IsWrapper() can be fully inlined by
|
||||
// jsfriendapi users.
|
||||
|
|
|
@ -86,6 +86,8 @@ EXPORTS.js += [
|
|||
'../public/StructuredClone.h',
|
||||
'../public/TracingAPI.h',
|
||||
'../public/TypeDecls.h',
|
||||
'../public/UbiNode.h',
|
||||
'../public/UbiNodeTraverse.h',
|
||||
'../public/Utility.h',
|
||||
'../public/Value.h',
|
||||
'../public/Vector.h',
|
||||
|
@ -123,6 +125,12 @@ UNIFIED_SOURCES += [
|
|||
'gc/Tracer.cpp',
|
||||
'gc/Verifier.cpp',
|
||||
'gc/Zone.cpp',
|
||||
'irregexp/RegExpAST.cpp',
|
||||
'irregexp/RegExpEngine.cpp',
|
||||
'irregexp/RegExpInterpreter.cpp',
|
||||
'irregexp/RegExpMacroAssembler.cpp',
|
||||
'irregexp/RegExpParser.cpp',
|
||||
'irregexp/RegExpStack.cpp',
|
||||
'jsalloc.cpp',
|
||||
'jsapi.cpp',
|
||||
'jsbool.cpp',
|
||||
|
@ -191,6 +199,7 @@ UNIFIED_SOURCES += [
|
|||
'vm/StructuredClone.cpp',
|
||||
'vm/ThreadPool.cpp',
|
||||
'vm/TypedArrayObject.cpp',
|
||||
'vm/UbiNode.cpp',
|
||||
'vm/Unicode.cpp',
|
||||
'vm/Value.cpp',
|
||||
'vm/WeakMapPtr.cpp',
|
||||
|
@ -231,42 +240,9 @@ if CONFIG['ENABLE_TRACE_LOGGING']:
|
|||
'vm/TraceLogging.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['ENABLE_YARR']:
|
||||
UNIFIED_SOURCES += [
|
||||
'yarr/PageBlock.cpp',
|
||||
'yarr/YarrCanonicalizeUCS2.cpp',
|
||||
'yarr/YarrInterpreter.cpp',
|
||||
'yarr/YarrPattern.cpp',
|
||||
'yarr/YarrSyntaxChecker.cpp',
|
||||
]
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
SOURCES += [
|
||||
'yarr/OSAllocatorWin.cpp',
|
||||
]
|
||||
else:
|
||||
SOURCES += [
|
||||
'yarr/OSAllocatorPosix.cpp',
|
||||
]
|
||||
if CONFIG['ENABLE_ION']:
|
||||
SOURCES += [
|
||||
'yarr/YarrJIT.cpp'
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'irregexp/RegExpAST.cpp',
|
||||
'irregexp/RegExpEngine.cpp',
|
||||
'irregexp/RegExpInterpreter.cpp',
|
||||
'irregexp/RegExpMacroAssembler.cpp',
|
||||
'irregexp/RegExpParser.cpp',
|
||||
'irregexp/RegExpStack.cpp',
|
||||
]
|
||||
if CONFIG['ENABLE_ION']:
|
||||
UNIFIED_SOURCES += [
|
||||
'irregexp/NativeRegExpMacroAssembler.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['ENABLE_ION']:
|
||||
UNIFIED_SOURCES += [
|
||||
'irregexp/NativeRegExpMacroAssembler.cpp',
|
||||
'jit/AliasAnalysis.cpp',
|
||||
'jit/AsmJS.cpp',
|
||||
'jit/AsmJSLink.cpp',
|
||||
|
|
|
@ -83,6 +83,10 @@ var Match =
|
|||
return (x !== null) && (typeof x === "object");
|
||||
}
|
||||
|
||||
function isFunction(x) {
|
||||
return typeof x === "function";
|
||||
}
|
||||
|
||||
function isArrayLike(x) {
|
||||
return isObject(x) && ("length" in x);
|
||||
}
|
||||
|
@ -134,6 +138,15 @@ var Match =
|
|||
return true;
|
||||
}
|
||||
|
||||
function matchFunction(act, exp) {
|
||||
if (!isFunction(act))
|
||||
throw new MatchError("expected function, got " + quote(act));
|
||||
|
||||
if (act !== exp)
|
||||
throw new MatchError("expected function: " + exp +
|
||||
"\nbut got different function: " + act);
|
||||
}
|
||||
|
||||
function matchArray(act, exp) {
|
||||
if (!isObject(act) || !("length" in act))
|
||||
throw new MatchError("expected array-like object, got " + quote(act));
|
||||
|
@ -166,6 +179,9 @@ var Match =
|
|||
if (isArrayLike(exp))
|
||||
return matchArray(act, exp);
|
||||
|
||||
if (isFunction(exp))
|
||||
return matchFunction(act, exp);
|
||||
|
||||
return matchObject(act, exp);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,3 +28,4 @@ user_pref("browser.safebrowsing.malware.enabled", false);
|
|||
user_pref("browser.snippets.enabled", false);
|
||||
user_pref("browser.snippets.syncPromo.enabled", false);
|
||||
user_pref("general.useragent.updates.enabled", false);
|
||||
user_pref("browser.webapps.checkForUpdates", 0);
|
||||
|
|
|
@ -150,28 +150,6 @@ class VectorMatchPairs : public MatchPairs
|
|||
bool allocOrExpandArray(size_t pairCount);
|
||||
};
|
||||
|
||||
/*
|
||||
* Passes either MatchPair or MatchPairs through ExecuteRegExp()
|
||||
* to avoid duplication of generic code.
|
||||
*/
|
||||
struct MatchConduit
|
||||
{
|
||||
union {
|
||||
MatchPair *pair;
|
||||
MatchPairs *pairs;
|
||||
} u;
|
||||
bool isPair;
|
||||
|
||||
explicit MatchConduit(MatchPair *pair) {
|
||||
isPair = true;
|
||||
u.pair = pair;
|
||||
}
|
||||
explicit MatchConduit(MatchPairs *pairs) {
|
||||
isPair = false;
|
||||
u.pairs = pairs;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_MatchPairs_h */
|
||||
|
|
|
@ -11,17 +11,12 @@
|
|||
#include "jsstr.h"
|
||||
|
||||
#include "frontend/TokenStream.h"
|
||||
#ifndef JS_YARR
|
||||
#include "irregexp/RegExpParser.h"
|
||||
#endif
|
||||
#include "vm/MatchPairs.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
#include "vm/Xdr.h"
|
||||
#ifdef JS_YARR
|
||||
#include "yarr/YarrSyntaxChecker.h"
|
||||
#endif
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
|
@ -306,10 +301,6 @@ RegExpObject *
|
|||
RegExpObject::createNoStatics(ExclusiveContext *cx, HandleAtom source, RegExpFlag flags,
|
||||
TokenStream *tokenStream, LifoAlloc &alloc)
|
||||
{
|
||||
#ifdef JS_YARR
|
||||
if (!RegExpShared::checkSyntax(cx, tokenStream, source))
|
||||
return nullptr;
|
||||
#else // JS_YARR
|
||||
Maybe<CompileOptions> dummyOptions;
|
||||
Maybe<TokenStream> dummyTokenStream;
|
||||
if (!tokenStream) {
|
||||
|
@ -322,7 +313,6 @@ RegExpObject::createNoStatics(ExclusiveContext *cx, HandleAtom source, RegExpFla
|
|||
|
||||
if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source))
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
RegExpObjectBuilder builder(cx);
|
||||
return builder.build(source, flags);
|
||||
|
@ -437,25 +427,13 @@ RegExpObject::toString(JSContext *cx) const
|
|||
/* RegExpShared */
|
||||
|
||||
RegExpShared::RegExpShared(JSAtom *source, RegExpFlag flags)
|
||||
: source(source), flags(flags), parenCount(0), canStringMatch(false), marked_(false)
|
||||
{
|
||||
#ifdef JS_YARR
|
||||
bytecode = nullptr;
|
||||
#else
|
||||
byteCode = nullptr;
|
||||
#endif
|
||||
}
|
||||
: source(source), flags(flags), parenCount(0), canStringMatch(false), marked_(false),
|
||||
byteCode(nullptr)
|
||||
{}
|
||||
|
||||
RegExpShared::~RegExpShared()
|
||||
{
|
||||
#ifdef JS_YARR
|
||||
#ifdef JS_ION
|
||||
codeBlock.release();
|
||||
#endif
|
||||
js_delete<BytecodePattern>(bytecode);
|
||||
#else // JS_YARR
|
||||
js_free(byteCode);
|
||||
#endif // JS_YARR
|
||||
|
||||
for (size_t i = 0; i < tables.length(); i++)
|
||||
js_delete(tables[i]);
|
||||
|
@ -470,68 +448,21 @@ RegExpShared::trace(JSTracer *trc)
|
|||
if (source)
|
||||
MarkString(trc, &source, "RegExpShared source");
|
||||
|
||||
#if !defined(JS_YARR) && defined(JS_ION)
|
||||
#ifdef JS_ION
|
||||
if (jitCode)
|
||||
MarkJitCode(trc, &jitCode, "RegExpShared code");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
void
|
||||
RegExpShared::reportYarrError(ExclusiveContext *cx, TokenStream *ts, ErrorCode error)
|
||||
{
|
||||
switch (error) {
|
||||
case JSC::Yarr::NoError:
|
||||
MOZ_ASSUME_UNREACHABLE("Called reportYarrError with value for no error");
|
||||
#define COMPILE_EMSG(__code, __msg) \
|
||||
case JSC::Yarr::__code: \
|
||||
if (ts) \
|
||||
ts->reportError(__msg); \
|
||||
else \
|
||||
JS_ReportErrorFlagsAndNumberUC(cx->asJSContext(), \
|
||||
JSREPORT_ERROR, js_GetErrorMessage, nullptr, __msg); \
|
||||
return
|
||||
COMPILE_EMSG(PatternTooLarge, JSMSG_REGEXP_TOO_COMPLEX);
|
||||
COMPILE_EMSG(QuantifierOutOfOrder, JSMSG_BAD_QUANTIFIER);
|
||||
COMPILE_EMSG(QuantifierWithoutAtom, JSMSG_BAD_QUANTIFIER);
|
||||
COMPILE_EMSG(MissingParentheses, JSMSG_MISSING_PAREN);
|
||||
COMPILE_EMSG(ParenthesesUnmatched, JSMSG_UNMATCHED_RIGHT_PAREN);
|
||||
COMPILE_EMSG(ParenthesesTypeInvalid, JSMSG_BAD_QUANTIFIER); /* "(?" with bad next char */
|
||||
COMPILE_EMSG(CharacterClassUnmatched, JSMSG_BAD_CLASS_RANGE);
|
||||
COMPILE_EMSG(CharacterClassInvalidRange, JSMSG_BAD_CLASS_RANGE);
|
||||
COMPILE_EMSG(CharacterClassOutOfOrder, JSMSG_BAD_CLASS_RANGE);
|
||||
COMPILE_EMSG(QuantifierTooLarge, JSMSG_BAD_QUANTIFIER);
|
||||
COMPILE_EMSG(EscapeUnterminated, JSMSG_TRAILING_SLASH);
|
||||
COMPILE_EMSG(RuntimeError, JSMSG_REGEXP_RUNTIME_ERROR);
|
||||
#undef COMPILE_EMSG
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Unknown Yarr error code");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RegExpShared::checkSyntax(ExclusiveContext *cx, TokenStream *tokenStream, JSLinearString *source)
|
||||
{
|
||||
ErrorCode error = JSC::Yarr::checkSyntax(*source);
|
||||
if (error == JSC::Yarr::NoError)
|
||||
return true;
|
||||
|
||||
reportYarrError(cx, tokenStream, error);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // JS_YARR
|
||||
|
||||
bool
|
||||
RegExpShared::compile(JSContext *cx, bool matchOnly, const jschar *sampleChars, size_t sampleLength)
|
||||
RegExpShared::compile(JSContext *cx, const jschar *sampleChars, size_t sampleLength)
|
||||
{
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
AutoTraceLog logCompile(logger, TraceLogger::IrregexpCompile);
|
||||
|
||||
if (!sticky()) {
|
||||
RootedAtom pattern(cx, source);
|
||||
return compile(cx, pattern, matchOnly, sampleChars, sampleLength);
|
||||
return compile(cx, pattern, sampleChars, sampleLength);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -554,11 +485,11 @@ RegExpShared::compile(JSContext *cx, bool matchOnly, const jschar *sampleChars,
|
|||
if (!fakeySource)
|
||||
return false;
|
||||
|
||||
return compile(cx, fakeySource, matchOnly, sampleChars, sampleLength);
|
||||
return compile(cx, fakeySource, sampleChars, sampleLength);
|
||||
}
|
||||
|
||||
bool
|
||||
RegExpShared::compile(JSContext *cx, HandleAtom pattern, bool matchOnly, const jschar *sampleChars, size_t sampleLength)
|
||||
RegExpShared::compile(JSContext *cx, HandleAtom pattern, const jschar *sampleChars, size_t sampleLength)
|
||||
{
|
||||
if (!ignoreCase() && !StringHasRegExpMetaChars(pattern->chars(), pattern->length())) {
|
||||
canStringMatch = true;
|
||||
|
@ -566,47 +497,6 @@ RegExpShared::compile(JSContext *cx, HandleAtom pattern, bool matchOnly, const j
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
ErrorCode yarrError;
|
||||
YarrPattern yarrPattern(*pattern, ignoreCase(), multiline(), &yarrError);
|
||||
if (yarrError) {
|
||||
reportYarrError(cx, nullptr, yarrError);
|
||||
return false;
|
||||
}
|
||||
this->parenCount = yarrPattern.m_numSubpatterns;
|
||||
|
||||
#ifdef JS_ION
|
||||
if (isJITRuntimeEnabled(cx) && !yarrPattern.m_containsBackreferences) {
|
||||
JSC::ExecutableAllocator *execAlloc = cx->runtime()->getExecAlloc(cx);
|
||||
if (!execAlloc)
|
||||
return false;
|
||||
|
||||
JSGlobalData globalData(execAlloc);
|
||||
YarrJITCompileMode compileMode = matchOnly ? JSC::Yarr::MatchOnly
|
||||
: JSC::Yarr::IncludeSubpatterns;
|
||||
|
||||
jitCompile(yarrPattern, JSC::Yarr::Char16, &globalData, codeBlock, compileMode);
|
||||
|
||||
/* Unset iff the Yarr JIT compilation was successful. */
|
||||
if (!codeBlock.isFallBack())
|
||||
return true;
|
||||
}
|
||||
codeBlock.setFallBack(true);
|
||||
#endif
|
||||
|
||||
WTF::BumpPointerAllocator *bumpAlloc = cx->runtime()->getBumpPointerAllocator(cx);
|
||||
if (!bumpAlloc) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
bytecode = byteCompile(yarrPattern, bumpAlloc).get();
|
||||
|
||||
#else // JS_YARR
|
||||
|
||||
JS_ASSERT(!matchOnly);
|
||||
|
||||
CompileOptions options(cx);
|
||||
TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
|
||||
|
||||
|
@ -632,29 +522,17 @@ RegExpShared::compile(JSContext *cx, HandleAtom pattern, bool matchOnly, const j
|
|||
|
||||
byteCode = code.byteCode;
|
||||
|
||||
#endif // JS_YARR
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RegExpShared::compileIfNecessary(JSContext *cx, const jschar *sampleChars, size_t sampleLength)
|
||||
{
|
||||
if (isCompiled(false) || canStringMatch)
|
||||
if (isCompiled() || canStringMatch)
|
||||
return true;
|
||||
return compile(cx, false, sampleChars, sampleLength);
|
||||
return compile(cx, sampleChars, sampleLength);
|
||||
}
|
||||
|
||||
#ifdef JS_YARR
|
||||
bool
|
||||
RegExpShared::compileMatchOnlyIfNecessary(JSContext *cx)
|
||||
{
|
||||
if (isCompiled(true) || canStringMatch)
|
||||
return true;
|
||||
return compile(cx, true, nullptr, 0);
|
||||
}
|
||||
#endif // JS_YARR
|
||||
|
||||
RegExpRunStatus
|
||||
RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
|
||||
size_t *lastIndex, MatchPairs &matches)
|
||||
|
@ -684,10 +562,8 @@ RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
|
|||
start = 0;
|
||||
}
|
||||
|
||||
#ifndef JS_YARR
|
||||
// Reset the Irregexp backtrack stack if it grows during execution.
|
||||
irregexp::RegExpStackScope stackScope(cx->runtime());
|
||||
#endif
|
||||
|
||||
if (canStringMatch) {
|
||||
int res = StringFindPattern(chars+start, length-start, source->chars(), source->length());
|
||||
|
@ -703,39 +579,6 @@ RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
|
|||
return RegExpRunStatus_Success;
|
||||
}
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
unsigned result;
|
||||
|
||||
// Yarr wants plain integers for its output buffer (whatever).
|
||||
JS_STATIC_ASSERT(sizeof(int32_t) == sizeof(int));
|
||||
JS_STATIC_ASSERT(sizeof(int32_t) == sizeof(unsigned));
|
||||
|
||||
#ifdef JS_ION
|
||||
if (codeBlock.isFallBack()) {
|
||||
AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret);
|
||||
result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, (unsigned *) matches.pairsRaw());
|
||||
} else {
|
||||
AutoTraceLog logJIT(logger, TraceLogger::YarrJIT);
|
||||
result = codeBlock.execute(chars, start, length, (int *) matches.pairsRaw()).start;
|
||||
}
|
||||
#else // JS_ION
|
||||
{
|
||||
AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret);
|
||||
result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, (unsigned *) matches.pairsRaw());
|
||||
}
|
||||
#endif // JS_ION
|
||||
|
||||
if (result == JSC::Yarr::offsetError) {
|
||||
reportYarrError(cx, nullptr, JSC::Yarr::RuntimeError);
|
||||
return RegExpRunStatus_Error;
|
||||
}
|
||||
|
||||
if (result == JSC::Yarr::offsetNoMatch)
|
||||
return RegExpRunStatus_Success_NotFound;
|
||||
|
||||
#else // JS_YARR
|
||||
|
||||
if (hasByteCode()) {
|
||||
AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
|
||||
RegExpRunStatus result =
|
||||
|
@ -786,111 +629,19 @@ RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
|
|||
MOZ_CRASH();
|
||||
#endif // JS_ION
|
||||
|
||||
#endif // JS_YARR
|
||||
|
||||
matches.displace(displacement);
|
||||
matches.checkAgainst(origLength);
|
||||
*lastIndex = matches[0].limit;
|
||||
return RegExpRunStatus_Success;
|
||||
}
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
RegExpRunStatus
|
||||
RegExpShared::executeMatchOnly(JSContext *cx, const jschar *chars, size_t length,
|
||||
size_t *lastIndex, MatchPair &match)
|
||||
{
|
||||
TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
|
||||
/* Compile the code at point-of-use. */
|
||||
if (!compileMatchOnlyIfNecessary(cx))
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
#ifdef DEBUG
|
||||
const size_t origLength = length;
|
||||
#endif
|
||||
size_t start = *lastIndex;
|
||||
size_t displacement = 0;
|
||||
|
||||
if (sticky()) {
|
||||
displacement = start;
|
||||
chars += displacement;
|
||||
length -= displacement;
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if (canStringMatch) {
|
||||
int res = StringFindPattern(chars+start, length-start, source->chars(), source->length());
|
||||
if (res == -1)
|
||||
return RegExpRunStatus_Success_NotFound;
|
||||
|
||||
match = MatchPair(res + start, res + start + source->length());
|
||||
match.displace(displacement);
|
||||
*lastIndex = match.limit;
|
||||
return RegExpRunStatus_Success;
|
||||
}
|
||||
|
||||
#ifdef JS_ION
|
||||
if (!codeBlock.isFallBack()) {
|
||||
AutoTraceLog logJIT(logger, TraceLogger::YarrJIT);
|
||||
MatchResult result = codeBlock.execute(chars, start, length);
|
||||
if (!result)
|
||||
return RegExpRunStatus_Success_NotFound;
|
||||
|
||||
match = MatchPair(result.start, result.end);
|
||||
match.displace(displacement);
|
||||
*lastIndex = match.limit;
|
||||
return RegExpRunStatus_Success;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The JIT could not be used, so fall back to the Yarr interpreter.
|
||||
* Unfortunately, the interpreter does not have a MatchOnly mode, so a
|
||||
* temporary output vector must be provided.
|
||||
*/
|
||||
JS_ASSERT(hasBytecode());
|
||||
ScopedMatchPairs matches(&cx->tempLifoAlloc());
|
||||
if (!matches.initArray(pairCount()))
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
unsigned result;
|
||||
{
|
||||
AutoTraceLog logInterpret(logger, TraceLogger::YarrInterpret);
|
||||
result = JSC::Yarr::interpret(cx, bytecode, chars, length, start, (unsigned *) matches.pairsRaw());
|
||||
}
|
||||
|
||||
if (result == JSC::Yarr::offsetError) {
|
||||
reportYarrError(cx, nullptr, JSC::Yarr::RuntimeError);
|
||||
return RegExpRunStatus_Error;
|
||||
}
|
||||
|
||||
if (result == JSC::Yarr::offsetNoMatch)
|
||||
return RegExpRunStatus_Success_NotFound;
|
||||
|
||||
match = MatchPair(result, matches[0].limit);
|
||||
match.displace(displacement);
|
||||
|
||||
#ifdef DEBUG
|
||||
matches.displace(displacement);
|
||||
matches.checkAgainst(origLength);
|
||||
#endif
|
||||
|
||||
*lastIndex = match.limit;
|
||||
return RegExpRunStatus_Success;
|
||||
}
|
||||
|
||||
#endif // JS_YARR
|
||||
|
||||
size_t
|
||||
RegExpShared::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
size_t n = mallocSizeOf(this);
|
||||
|
||||
#ifndef JS_YARR
|
||||
if (byteCode)
|
||||
n += mallocSizeOf(byteCode);
|
||||
#endif
|
||||
|
||||
n += tables.sizeOfExcludingThis(mallocSizeOf);
|
||||
for (size_t i = 0; i < tables.length(); i++)
|
||||
|
@ -979,7 +730,7 @@ RegExpCompartment::sweep(JSRuntime *rt)
|
|||
// the RegExpShared if it was accidentally marked earlier but wasn't
|
||||
// marked by the current trace.
|
||||
bool keep = shared->marked() && !IsStringAboutToBeFinalized(shared->source.unsafeGet());
|
||||
#if !defined(JS_YARR) && defined(JS_ION)
|
||||
#ifdef JS_ION
|
||||
if (keep && shared->jitCode)
|
||||
keep = !IsJitCodeAboutToBeFinalized(shared->jitCode.unsafeGet());
|
||||
#endif
|
||||
|
|
|
@ -17,13 +17,6 @@
|
|||
#include "gc/Zone.h"
|
||||
#include "vm/Shape.h"
|
||||
|
||||
#ifdef JS_YARR
|
||||
#ifdef JS_ION
|
||||
#include "yarr/YarrJIT.h"
|
||||
#endif
|
||||
#include "yarr/YarrInterpreter.h"
|
||||
#endif // JS_YARR
|
||||
|
||||
/*
|
||||
* JavaScript Regular Expressions
|
||||
*
|
||||
|
@ -111,17 +104,6 @@ class RegExpShared
|
|||
|
||||
typedef frontend::TokenStream TokenStream;
|
||||
|
||||
#ifdef JS_YARR
|
||||
typedef JSC::Yarr::BytecodePattern BytecodePattern;
|
||||
typedef JSC::Yarr::ErrorCode ErrorCode;
|
||||
typedef JSC::Yarr::YarrPattern YarrPattern;
|
||||
#ifdef JS_ION
|
||||
typedef JSC::Yarr::JSGlobalData JSGlobalData;
|
||||
typedef JSC::Yarr::YarrCodeBlock YarrCodeBlock;
|
||||
typedef JSC::Yarr::YarrJITCompileMode YarrJITCompileMode;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Source to the RegExp, for lazy compilation. */
|
||||
HeapPtrAtom source;
|
||||
|
||||
|
@ -130,69 +112,28 @@ class RegExpShared
|
|||
bool canStringMatch;
|
||||
bool marked_;
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
#ifdef JS_ION
|
||||
/* Note: Native code is valid only if |codeBlock.isFallBack() == false|. */
|
||||
YarrCodeBlock codeBlock;
|
||||
#endif
|
||||
BytecodePattern *bytecode;
|
||||
|
||||
#else // JS_YARR
|
||||
|
||||
#ifdef JS_ION
|
||||
HeapPtrJitCode jitCode;
|
||||
#endif
|
||||
uint8_t *byteCode;
|
||||
|
||||
#endif // JS_YARR
|
||||
|
||||
// Tables referenced by JIT code.
|
||||
Vector<uint8_t *, 0, SystemAllocPolicy> tables;
|
||||
|
||||
/* Internal functions. */
|
||||
bool compile(JSContext *cx, bool matchOnly, const jschar *sampleChars, size_t sampleLength);
|
||||
bool compile(JSContext *cx, HandleAtom pattern, bool matchOnly, const jschar *sampleChars, size_t sampleLength);
|
||||
bool compile(JSContext *cx, const jschar *sampleChars, size_t sampleLength);
|
||||
bool compile(JSContext *cx, HandleAtom pattern, const jschar *sampleChars, size_t sampleLength);
|
||||
|
||||
bool compileIfNecessary(JSContext *cx, const jschar *sampleChars, size_t sampleLength);
|
||||
|
||||
#ifdef JS_YARR
|
||||
bool compileMatchOnlyIfNecessary(JSContext *cx);
|
||||
#endif
|
||||
|
||||
public:
|
||||
RegExpShared(JSAtom *source, RegExpFlag flags);
|
||||
~RegExpShared();
|
||||
|
||||
#ifdef JS_YARR
|
||||
/* Static functions to expose some Yarr logic. */
|
||||
|
||||
// This function should be deleted once bad Android platforms phase out. See bug 604774.
|
||||
static bool isJITRuntimeEnabled(JSContext *cx) {
|
||||
#ifdef JS_ION
|
||||
# if defined(ANDROID)
|
||||
return !cx->jitIsBroken;
|
||||
# else
|
||||
return true;
|
||||
# endif
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
static void reportYarrError(ExclusiveContext *cx, TokenStream *ts, ErrorCode error);
|
||||
static bool checkSyntax(ExclusiveContext *cx, TokenStream *tokenStream, JSLinearString *source);
|
||||
#endif // JS_YARR
|
||||
|
||||
/* Primary interface: run this regular expression on the given string. */
|
||||
RegExpRunStatus execute(JSContext *cx, const jschar *chars, size_t length,
|
||||
size_t *lastIndex, MatchPairs &matches);
|
||||
|
||||
#ifdef JS_YARR
|
||||
/* Run the regular expression without collecting matches, for test(). */
|
||||
RegExpRunStatus executeMatchOnly(JSContext *cx, const jschar *chars, size_t length,
|
||||
size_t *lastIndex, MatchPair &match);
|
||||
#endif
|
||||
|
||||
// Register a table with this RegExpShared, and take ownership.
|
||||
bool addTable(uint8_t *table) {
|
||||
return tables.append(table);
|
||||
|
@ -201,7 +142,7 @@ class RegExpShared
|
|||
/* Accessors */
|
||||
|
||||
size_t getParenCount() const {
|
||||
JS_ASSERT(isCompiled(true) || isCompiled(false) || canStringMatch);
|
||||
JS_ASSERT(isCompiled() || canStringMatch);
|
||||
return parenCount;
|
||||
}
|
||||
|
||||
|
@ -215,24 +156,6 @@ class RegExpShared
|
|||
bool multiline() const { return flags & MultilineFlag; }
|
||||
bool sticky() const { return flags & StickyFlag; }
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
bool hasCode(bool matchOnly) const {
|
||||
#ifdef JS_ION
|
||||
return matchOnly ? codeBlock.has16BitCodeMatchOnly() : codeBlock.has16BitCode();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
bool hasBytecode() const {
|
||||
return bytecode != nullptr;
|
||||
}
|
||||
bool isCompiled(bool matchOnly) const {
|
||||
return hasBytecode() || hasCode(matchOnly);
|
||||
}
|
||||
|
||||
#else // JS_YARR
|
||||
|
||||
bool hasJitCode() const {
|
||||
#ifdef JS_ION
|
||||
return jitCode != nullptr;
|
||||
|
@ -244,12 +167,10 @@ class RegExpShared
|
|||
return byteCode != nullptr;
|
||||
}
|
||||
|
||||
bool isCompiled(bool matchOnly) const {
|
||||
bool isCompiled() const {
|
||||
return hasJitCode() || hasByteCode();
|
||||
}
|
||||
|
||||
#endif // JS_YARR
|
||||
|
||||
void trace(JSTracer *trc);
|
||||
|
||||
bool marked() const { return marked_; }
|
||||
|
|
|
@ -39,9 +39,6 @@
|
|||
#include "jit/PcScriptCache.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/SliceBudget.h"
|
||||
#ifdef JS_YARR
|
||||
#include "yarr/BumpPointerAllocator.h"
|
||||
#endif
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsgcinlines.h"
|
||||
|
@ -110,10 +107,8 @@ PerThreadData::init()
|
|||
if (!dtoaState)
|
||||
return false;
|
||||
|
||||
#ifndef JS_YARR
|
||||
if (!regexpStack.init())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -157,9 +152,6 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
|
|||
tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
|
||||
freeLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
|
||||
execAlloc_(nullptr),
|
||||
#ifdef JS_YARR
|
||||
bumpAlloc_(nullptr),
|
||||
#endif
|
||||
jitRuntime_(nullptr),
|
||||
selfHostingGlobal_(nullptr),
|
||||
nativeStackBase(0),
|
||||
|
@ -439,9 +431,6 @@ JSRuntime::~JSRuntime()
|
|||
atomsCompartment_ = nullptr;
|
||||
|
||||
js_free(defaultLocale);
|
||||
#ifdef JS_YARR
|
||||
js_delete(bumpAlloc_);
|
||||
#endif
|
||||
js_delete(mathCache_);
|
||||
#ifdef JS_ION
|
||||
js_delete(jitRuntime_);
|
||||
|
@ -518,10 +507,6 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim
|
|||
|
||||
rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
#ifdef JS_YARR
|
||||
rtSizes->regexpData += bumpAlloc_ ? bumpAlloc_->sizeOfNonHeapData() : 0;
|
||||
#endif
|
||||
|
||||
rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
|
||||
|
@ -604,22 +589,6 @@ JSRuntime::createExecutableAllocator(JSContext *cx)
|
|||
return execAlloc_;
|
||||
}
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
WTF::BumpPointerAllocator *
|
||||
JSRuntime::createBumpPointerAllocator(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(!bumpAlloc_);
|
||||
JS_ASSERT(cx->runtime() == this);
|
||||
|
||||
bumpAlloc_ = js_new<WTF::BumpPointerAllocator>();
|
||||
if (!bumpAlloc_)
|
||||
js_ReportOutOfMemory(cx);
|
||||
return bumpAlloc_;
|
||||
}
|
||||
|
||||
#endif // JS_YARR
|
||||
|
||||
MathCache *
|
||||
JSRuntime::createMathCache(JSContext *cx)
|
||||
{
|
||||
|
|
|
@ -28,9 +28,7 @@
|
|||
#include "frontend/ParseMaps.h"
|
||||
#include "gc/GCRuntime.h"
|
||||
#include "gc/Tracer.h"
|
||||
#ifndef JS_YARR
|
||||
#include "irregexp/RegExpStack.h"
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
# include "jit/AsmJSSignalHandlers.h"
|
||||
#endif
|
||||
|
@ -75,10 +73,6 @@ js_ReportOverRecursed(js::ThreadSafeContext *cx);
|
|||
|
||||
namespace JSC { class ExecutableAllocator; }
|
||||
|
||||
#ifdef JS_YARR
|
||||
namespace WTF { class BumpPointerAllocator; }
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
class Activation;
|
||||
|
@ -499,10 +493,8 @@ class PerThreadData : public PerThreadDataFriendFields
|
|||
|
||||
inline void setJitStackLimit(uintptr_t limit);
|
||||
|
||||
#ifndef JS_YARR
|
||||
// Information about the heap allocated backtrack stack used by RegExp JIT code.
|
||||
irregexp::RegExpStack regexpStack;
|
||||
#endif
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLogger *traceLogger;
|
||||
|
@ -610,10 +602,21 @@ class PerThreadData : public PerThreadDataFriendFields
|
|||
{
|
||||
JS_ASSERT(!pt->runtime_);
|
||||
pt->runtime_ = rt;
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
// The simulator has a pointer to its SimulatorRuntime, but helper threads
|
||||
// don't have a simulator as they don't run JIT code so this pointer need not
|
||||
// be updated. All the paths that the helper threads use access the
|
||||
// SimulatorRuntime via the PerThreadData.
|
||||
JS_ASSERT(!pt->simulator_);
|
||||
#endif
|
||||
}
|
||||
|
||||
~AutoEnterRuntime() {
|
||||
pt->runtime_ = nullptr;
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
// Check that helper threads have not run JIT code and/or added a simulator.
|
||||
JS_ASSERT(!pt->simulator_);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -809,9 +812,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
* thread-data level.
|
||||
*/
|
||||
JSC::ExecutableAllocator *execAlloc_;
|
||||
#ifdef JS_YARR
|
||||
WTF::BumpPointerAllocator *bumpAlloc_;
|
||||
#endif
|
||||
js::jit::JitRuntime *jitRuntime_;
|
||||
|
||||
/*
|
||||
|
@ -824,9 +824,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
js::InterpreterStack interpreterStack_;
|
||||
|
||||
JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx);
|
||||
#ifdef JS_YARR
|
||||
WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx);
|
||||
#endif
|
||||
js::jit::JitRuntime *createJitRuntime(JSContext *cx);
|
||||
|
||||
public:
|
||||
|
@ -840,11 +837,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
JSC::ExecutableAllocator *maybeExecAlloc() {
|
||||
return execAlloc_;
|
||||
}
|
||||
#ifdef JS_YARR
|
||||
WTF::BumpPointerAllocator *getBumpPointerAllocator(JSContext *cx) {
|
||||
return bumpAlloc_ ? bumpAlloc_ : createBumpPointerAllocator(cx);
|
||||
}
|
||||
#endif
|
||||
js::jit::JitRuntime *getJitRuntime(JSContext *cx) {
|
||||
return jitRuntime_ ? jitRuntime_ : createJitRuntime(cx);
|
||||
}
|
||||
|
|
|
@ -832,14 +832,8 @@ TraceLogging::lazyInit()
|
|||
enabledTextIds[TraceLogger::ParserCompileFunction] = true;
|
||||
enabledTextIds[TraceLogger::ParserCompileLazy] = true;
|
||||
enabledTextIds[TraceLogger::ParserCompileScript] = true;
|
||||
#ifdef JS_YARR
|
||||
enabledTextIds[TraceLogger::YarrCompile] = true;
|
||||
enabledTextIds[TraceLogger::YarrInterpret] = true;
|
||||
enabledTextIds[TraceLogger::YarrJIT] = true;
|
||||
#else
|
||||
enabledTextIds[TraceLogger::IrregexpCompile] = true;
|
||||
enabledTextIds[TraceLogger::IrregexpExecute] = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ContainsFlag(env, "IonCompiler") || strlen(env) == 0) {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче