Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-09-27 11:56:13 +01:00
commit b7e92a6866
108 changed files with 2829 additions and 1327 deletions

View File

@ -114,8 +114,10 @@ FocusManager::IsInOrContainsFocus(const Accessible* aAccessible) const
void
FocusManager::NotifyOfDOMFocus(nsISupports* aTarget)
{
A11YDEBUG_FOCUS_NOTIFICATION_SUPPORTSTARGET("DOM focus", "DOM focus target",
aTarget)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::FocusNotificationTarget("DOM focus", "Target", aTarget);
#endif
mActiveItem = nullptr;
@ -140,8 +142,10 @@ FocusManager::NotifyOfDOMFocus(nsISupports* aTarget)
void
FocusManager::NotifyOfDOMBlur(nsISupports* aTarget)
{
A11YDEBUG_FOCUS_NOTIFICATION_SUPPORTSTARGET("DOM blur", "DOM blur target",
aTarget)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::FocusNotificationTarget("DOM blur", "Target", aTarget);
#endif
mActiveItem = nullptr;
@ -162,8 +166,10 @@ FocusManager::NotifyOfDOMBlur(nsISupports* aTarget)
void
FocusManager::ActiveItemChanged(Accessible* aItem, bool aCheckIfActive)
{
A11YDEBUG_FOCUS_NOTIFICATION_ACCTARGET("active item changed",
"Active item", aItem)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::FocusNotificationTarget("active item changed", "Item", aItem);
#endif
// Nothing changed, happens for XUL trees and HTML selects.
if (aItem && aItem == mActiveItem)
@ -173,7 +179,10 @@ FocusManager::ActiveItemChanged(Accessible* aItem, bool aCheckIfActive)
if (aItem && aCheckIfActive) {
Accessible* widget = aItem->ContainerWidget();
A11YDEBUG_FOCUS_LOG_WIDGET("Active item widget", widget)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::ActiveWidget(widget);
#endif
if (!widget || !widget->IsActiveWidget() || !widget->AreItemsOperable())
return;
}
@ -212,15 +221,20 @@ FocusManager::DispatchFocusEvent(DocAccessible* aDocument,
eAutoDetect, AccEvent::eCoalesceOfSameType);
aDocument->FireDelayedAccessibleEvent(event);
A11YDEBUG_FOCUS_LOG_ACCTARGET("Focus notification", aTarget)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::FocusDispatched(aTarget);
#endif
}
}
void
FocusManager::ProcessDOMFocus(nsINode* aTarget)
{
A11YDEBUG_FOCUS_NOTIFICATION_DOMTARGET("Process DOM focus",
"Notification target", aTarget)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::FocusNotificationTarget("process DOM focus", "Target", aTarget);
#endif
DocAccessible* document =
GetAccService()->GetDocAccessible(aTarget->OwnerDoc());
@ -308,8 +322,10 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
mActiveARIAMenubar = nullptr;
}
A11YDEBUG_FOCUS_NOTIFICATION_ACCTARGET("FIRE FOCUS EVENT", "Focus target",
target)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::FocusNotificationTarget("fire focus event", "Target", target);
#endif
nsRefPtr<AccEvent> focusEvent =
new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, target, fromUserInputFlag);

View File

@ -128,126 +128,4 @@ private:
} // namespace a11y
} // namespace mozilla
//#define A11YDEBUG_FOCUS
#ifdef A11YDEBUG_FOCUS
// Util macros (don't use them directly)
#define A11YDEBUG_FOCUS_STARTBLOCK \
printf(" {\n ");
#define A11YDEBUG_FOCUS_ENDBLOCK \
printf("\n }\n");
#define A11YDEBUG_FOCUS_BLOCKOFFSET \
printf(" ");
#define A11YDEBUG_FOCUS_LOG_TIME \
{ \
PRIntervalTime time = PR_IntervalNow(); \
uint32_t mins = (PR_IntervalToSeconds(time) / 60) % 60; \
uint32_t secs = PR_IntervalToSeconds(time) % 60; \
uint32_t msecs = PR_IntervalToMilliseconds(time) % 1000; \
printf("Time: %2d:%2d.%3d\n", mins, secs, msecs); \
}
#define A11YDEBUG_FOCUS_LOG_DOMNODE(aNode) \
if (aNode) { \
if (aNode->IsElement()) { \
dom::Element* targetElm = aNode->AsElement(); \
nsAutoCString tag; \
targetElm->Tag()->ToUTF8String(tag); \
nsAutoCString id; \
nsIAtom* atomid = targetElm->GetID(); \
if (atomid) \
atomid->ToUTF8String(id); \
printf("element %s@id='%s': %p", tag.get(), id.get(), (void*)aNode); \
} else if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) { \
nsCOMPtr<nsIDocument> document = do_QueryInterface(aNode); \
nsIURI* uri = document->GetDocumentURI(); \
nsAutoCString spec; \
uri->GetSpec(spec); \
printf("document: %p; uri: %s", (void*)aNode, spec.get()); \
} \
}
#define A11YDEBUG_FOCUS_LOG_ACCESSIBLE(aAccessible) \
printf("accessible: %p; ", (void*)aAccessible); \
if (aAccessible) { \
nsAutoString role; \
GetAccService()->GetStringRole(aAccessible->Role(), role); \
nsAutoString name; \
aAccessible->Name(name); \
printf(" role: %s, name: %s; ", NS_ConvertUTF16toUTF8(role).get(), \
NS_ConvertUTF16toUTF8(name).get()); \
A11YDEBUG_FOCUS_LOG_DOMNODE(aAccessible->GetNode()) \
}
// Public macros
#define A11YDEBUG_FOCUS_LOG_DOMTARGET(aMsg, aTarget) \
A11YDEBUG_FOCUS_STARTBLOCK \
printf(aMsg "\n"); \
if (aTarget) { \
A11YDEBUG_FOCUS_BLOCKOFFSET \
A11YDEBUG_FOCUS_LOG_DOMNODE(aTarget) \
} \
A11YDEBUG_FOCUS_ENDBLOCK
#define A11YDEBUG_FOCUS_LOG_ACCTARGET(aMsg, aTarget) \
A11YDEBUG_FOCUS_STARTBLOCK \
printf(aMsg "\n"); \
A11YDEBUG_FOCUS_BLOCKOFFSET \
A11YDEBUG_FOCUS_LOG_ACCESSIBLE(aTarget) \
A11YDEBUG_FOCUS_ENDBLOCK
#define A11YDEBUG_FOCUS_LOG_WIDGET(aMsg, aWidget) \
A11YDEBUG_FOCUS_STARTBLOCK \
printf(aMsg "\n"); \
A11YDEBUG_FOCUS_BLOCKOFFSET \
A11YDEBUG_FOCUS_LOG_ACCESSIBLE(aWidget) \
printf("; widget is active: %s, has operable items: %s", \
(aWidget && aWidget->IsActiveWidget() ? "true" : "false"), \
(aWidget && aWidget->AreItemsOperable() ? "true" : "false")); \
A11YDEBUG_FOCUS_ENDBLOCK
#define A11YDEBUG_FOCUS_NOTIFICATION_SUPPORTSTARGET(aMsg, aTargetMsg, aTarget) \
printf("\nA11Y FOCUS: " aMsg ". "); \
A11YDEBUG_FOCUS_LOG_TIME \
if (aTarget) { \
A11YDEBUG_FOCUS_STARTBLOCK \
printf(aTargetMsg "\n"); \
A11YDEBUG_FOCUS_BLOCKOFFSET \
nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTarget)); \
if (targetNode) { \
A11YDEBUG_FOCUS_LOG_DOMNODE(targetNode) \
} else { \
printf("window: %p", (void*)aTarget); \
} \
A11YDEBUG_FOCUS_ENDBLOCK \
}
#define A11YDEBUG_FOCUS_NOTIFICATION_DOMTARGET(aMsg, aTargetMsg, aTarget) \
printf("\nA11Y FOCUS: " aMsg ". "); \
A11YDEBUG_FOCUS_LOG_TIME \
A11YDEBUG_FOCUS_LOG_DOMTARGET(aTargetMsg, aTarget)
#define A11YDEBUG_FOCUS_NOTIFICATION_ACCTARGET(aMsg, aTargetMsg, aTarget) \
printf("\nA11Y FOCUS: " aMsg ". "); \
A11YDEBUG_FOCUS_LOG_TIME \
A11YDEBUG_FOCUS_LOG_ACCTARGET(aTargetMsg, aTarget)
#define A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE(aMsg, aTarget) \
A11YDEBUG_FOCUS_LOG_ACCTARGET("Caused by: " aMsg, aTarget)
#else
#define A11YDEBUG_FOCUS_LOG_DOMTARGET(aMsg, aTarget)
#define A11YDEBUG_FOCUS_LOG_ACCTARGET(aMsg, aTarget)
#define A11YDEBUG_FOCUS_LOG_WIDGET(aMsg, aWidget)
#define A11YDEBUG_FOCUS_NOTIFICATION_SUPPORTSTARGET(aMsg, aTargetMsg, aTarget)
#define A11YDEBUG_FOCUS_NOTIFICATION_DOMTARGET(aMsg, aTargetMsg, aTarget)
#define A11YDEBUG_FOCUS_NOTIFICATION_ACCTARGET(aMsg, aTargetMsg, aTarget)
#define A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE(aMsg, aTarget)
#endif
#endif

View File

@ -6,6 +6,7 @@
#include "Logging.h"
#include "Accessible-inl.h"
#include "AccEvent.h"
#include "DocAccessible.h"
#include "nsAccessibilityService.h"
@ -350,6 +351,7 @@ static const char* sDocLoadTitle = "DOCLOAD";
static const char* sDocCreateTitle = "DOCCREATE";
static const char* sDocDestroyTitle = "DOCDESTROY";
static const char* sDocEventTitle = "DOCEVENT";
static const char* sFocusTitle = "FOCUS";
void
logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
@ -465,6 +467,72 @@ logging::OuterDocDestroy(OuterDocAccessible* aOuterDoc)
MsgEnd();
}
void
logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
Accessible* aTarget)
{
MsgBegin(sFocusTitle, aMsg);
AccessibleNNode(aTargetDescr, aTarget);
MsgEnd();
}
void
logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
nsINode* aTargetNode)
{
MsgBegin(sFocusTitle, aMsg);
Node(aTargetDescr, aTargetNode);
MsgEnd();
}
void
logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
nsISupports* aTargetThing)
{
MsgBegin(sFocusTitle, aMsg);
if (aTargetThing) {
nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTargetThing));
if (targetNode)
Node(aTargetDescr, targetNode);
else
printf(" %s: %p, window\n", aTargetDescr,
static_cast<void*>(aTargetThing));
}
MsgEnd();
}
void
logging::ActiveItemChangeCausedBy(const char* aCause, Accessible* aTarget)
{
SubMsgBegin();
printf(" Caused by: %s\n", aCause);
AccessibleNNode("Item", aTarget);
SubMsgEnd();
}
void
logging::ActiveWidget(Accessible* aWidget)
{
SubMsgBegin();
AccessibleNNode("Widget", aWidget);
printf(" Widget is active: %s, has operable items: %s\n",
(aWidget && aWidget->IsActiveWidget() ? "true" : "false"),
(aWidget && aWidget->AreItemsOperable() ? "true" : "false"));
SubMsgEnd();
}
void
logging::FocusDispatched(Accessible* aTarget)
{
SubMsgBegin();
AccessibleNNode("A11y target", aTarget);
SubMsgEnd();
}
void
logging::SelChange(nsISelection* aSelection, DocAccessible* aDocument)
{
@ -496,6 +564,12 @@ logging::MsgBegin(const char* aTitle, const char* aMsgText, ...)
vprintf(aMsgText, argptr);
va_end(argptr);
PRIntervalTime time = PR_IntervalNow();
uint32_t mins = (PR_IntervalToSeconds(time) / 60) % 60;
uint32_t secs = PR_IntervalToSeconds(time) % 60;
uint32_t msecs = PR_IntervalToMilliseconds(time) % 1000;
printf("; %02d:%02d.%03d", mins, secs, msecs);
printf("\n {\n");
}
@ -505,6 +579,18 @@ logging::MsgEnd()
printf(" }\n");
}
void
logging::SubMsgBegin()
{
printf(" {\n");
}
void
logging::SubMsgEnd()
{
printf(" }\n");
}
void
logging::MsgEntry(const char* aEntryText, ...)
{
@ -586,6 +672,34 @@ logging::Node(const char* aDescr, nsINode* aNode)
aDescr, static_cast<void*>(elm), tag.get(), id.get(), idxInParent);
}
void
logging::AccessibleNNode(const char* aDescr, Accessible* aAccessible)
{
printf(" %s: %p; ", aDescr, static_cast<void*>(aAccessible));
if (!aAccessible)
return;
nsAutoString role;
GetAccService()->GetStringRole(aAccessible->Role(), role);
nsAutoString name;
aAccessible->Name(name);
printf("role: %s, name: '%s';\n", NS_ConvertUTF16toUTF8(role).get(),
NS_ConvertUTF16toUTF8(name).get());
nsAutoCString nodeDescr(aDescr);
nodeDescr.AppendLiteral(" node");
Node(nodeDescr.get(), aAccessible->GetNode());
printf(" Document: %p, document node: %p\n",
static_cast<void*>(aAccessible->Document()),
static_cast<void*>(aAccessible->GetDocumentNode()));
printf(" Document");
LogDocURI(static_cast<nsIDocument*>(aAccessible->GetDocumentNode()));
printf("\n");
}
void
logging::Stack()
{

View File

@ -84,6 +84,31 @@ void DocDestroy(const char* aMsg, nsIDocument* aDocumentNode,
*/
void OuterDocDestroy(OuterDocAccessible* OuterDoc);
/**
* Log the focus notification target.
*/
void FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
Accessible* aTarget);
void FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
nsINode* aTargetNode);
void FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
nsISupports* aTargetThing);
/**
* Log a cause of active item descendant change (submessage).
*/
void ActiveItemChangeCausedBy(const char* aMsg, Accessible* aTarget);
/**
* Log the active widget (submessage).
*/
void ActiveWidget(Accessible* aWidget);
/**
* Log the focus event was dispatched (submessage).
*/
void FocusDispatched(Accessible* aTarget);
/**
* Log the selection change.
*/
@ -97,6 +122,13 @@ void SelChange(nsISelection* aSelection, DocAccessible* aDocument);
void MsgBegin(const char* aTitle, const char* aMsgText, ...);
void MsgEnd();
/**
* Print start and end boundaries of the message body designated by '{' and '}'
* (2 spaces indent for body).
*/
void SubMsgBegin();
void SubMsgEnd();
/**
* Log the entry into message body (4 spaces indent).
*/
@ -117,6 +149,11 @@ void Address(const char* aDescr, Accessible* aAcc);
*/
void Node(const char* aDescr, nsINode* aNode);
/**
* Log the accessible and its DOM node as a message entry.
*/
void AccessibleNNode(const char* aDescr, Accessible* aAccessible);
/**
* Log the call stack, two spaces offset is used.
*/

View File

@ -617,6 +617,7 @@ Accessible::VisibilityState()
return states::INVISIBLE;
nsIFrame* curFrame = frame;
nsPoint framePos(0, 0);
do {
nsIView* view = curFrame->GetView();
if (view && view->GetVisibility() == nsViewVisibility_kHide)
@ -628,6 +629,21 @@ Accessible::VisibilityState()
if (deckFrame && deckFrame->GetSelectedBox() != curFrame)
return states::OFFSCREEN;
// If contained by scrollable frame then check that at least 12 pixels
// around the object is visible, otherwise the object is offscreen.
framePos += curFrame->GetPosition();
nsIScrollableFrame* scrollableFrame = do_QueryFrame(parentFrame);
if (scrollableFrame) {
nsRect scrollPortRect = scrollableFrame->GetScrollPortRect();
nsRect frameRect(framePos, frame->GetSize());
if (!scrollPortRect.Contains(frameRect)) {
const nscoord kMinPixels = nsPresContext::CSSPixelsToAppUnits(12);
scrollPortRect.Deflate(kMinPixels, kMinPixels);
if (!scrollPortRect.Intersects(frameRect))
return states::OFFSCREEN;
}
}
if (!parentFrame) {
parentFrame = nsLayoutUtils::GetCrossDocParentFrame(curFrame);
if (parentFrame && !parentFrame->GetStyleVisibility()->IsVisible())
@ -651,17 +667,6 @@ Accessible::VisibilityState()
return states::INVISIBLE;
}
// We need to know if at least a kMinPixels around the object is visible,
// otherwise it will be marked states::OFFSCREEN.
const uint16_t kMinPixels = 12;
const nsSize frameSize = frame->GetSize();
const nsRectVisibility rectVisibility =
mDoc->PresShell()->GetRectVisibility(frame, nsRect(nsPoint(0,0), frameSize),
nsPresContext::CSSPixelsToAppUnits(kMinPixels));
if (rectVisibility != nsRectVisibility_kVisible)
return states::OFFSCREEN;
return 0;
}

View File

@ -1230,8 +1230,11 @@ DocAccessible::ARIAActiveDescendantChanged(nsIContent* aElm)
Accessible* activeDescendant = GetAccessible(activeDescendantElm);
if (activeDescendant) {
FocusMgr()->ActiveItemChanged(activeDescendant, false);
A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("ARIA activedescedant changed",
activeDescendant)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::ActiveItemChangeCausedBy("ARIA activedescedant changed",
activeDescendant);
#endif
}
}
}
@ -1413,7 +1416,10 @@ DocAccessible::UnbindFromDocument(Accessible* aAccessible)
// from the tree.
if (FocusMgr()->IsActiveItem(aAccessible)) {
FocusMgr()->ActiveItemChanged(nullptr);
A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("tree shutdown", aAccessible)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::ActiveItemChangeCausedBy("tree shutdown", aAccessible);
#endif
}
// Remove an accessible from node-to-accessible map if it exists there.

View File

@ -342,7 +342,10 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
if (isEnabled) {
FocusMgr()->ActiveItemChanged(accessible);
A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("RadioStateChange", accessible)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::ActiveItemChangeCausedBy("RadioStateChange", accessible);
#endif
}
return;
@ -421,7 +424,10 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
}
else if (eventType.EqualsLiteral("DOMMenuItemActive")) {
FocusMgr()->ActiveItemChanged(accessible);
A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuItemActive", accessible)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::ActiveItemChangeCausedBy("DOMMenuItemActive", accessible);
#endif
}
else if (eventType.EqualsLiteral("DOMMenuItemInactive")) {
// Process DOMMenuItemInactive event for autocomplete only because this is
@ -432,7 +438,10 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
accessible->IsWidget() ? accessible : accessible->ContainerWidget();
if (widget && widget->IsAutoCompletePopup()) {
FocusMgr()->ActiveItemChanged(nullptr);
A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuItemInactive", accessible)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::ActiveItemChangeCausedBy("DOMMenuItemInactive", accessible);
#endif
}
}
else if (eventType.EqualsLiteral("DOMMenuBarActive")) { // Always from user input
@ -448,7 +457,10 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
Accessible* activeItem = accessible->CurrentItem();
if (activeItem) {
FocusMgr()->ActiveItemChanged(activeItem);
A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuBarActive", accessible)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::ActiveItemChangeCausedBy("DOMMenuBarActive", accessible);
#endif
}
}
else if (eventType.EqualsLiteral("DOMMenuBarInactive")) { // Always from user input
@ -456,7 +468,10 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
accessible, eFromUserInput);
FocusMgr()->ActiveItemChanged(nullptr);
A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuBarInactive", accessible)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::ActiveItemChangeCausedBy("DOMMenuBarInactive", accessible);
#endif
}
else if (eventType.EqualsLiteral("ValueChange")) {
targetDocument->
@ -647,7 +662,10 @@ RootAccessible::HandlePopupHidingEvent(nsINode* aPopupNode)
// Restore focus to where it was.
if (notifyOf & kNotifyOfFocus) {
FocusMgr()->ActiveItemChanged(nullptr);
A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("popuphiding", popup)
#ifdef DEBUG
if (logging::IsEnabled(logging::eFocus))
logging::ActiveItemChangeCausedBy("popuphiding", popup);
#endif
}
// Fire expanded state change event.

View File

@ -50,6 +50,9 @@
gQueue.push(new synthEscapeKey("item2.1", new focusChecker("item2")));
gQueue.push(new synthEscapeKey("item2", new focusChecker("button")));
enableLogging("focus");
gQueue.onFinish = function() { disableLogging(); }
gQueue.invoke(); // Will call SimpleTest.finish();
}

View File

@ -71,6 +71,9 @@
// click menuitem to close menu, focus gets back to document
gQueue.push(new synthClick("tricycle", new focusChecker(document)));
enableLogging("focus");
gQueue.onFinish = function() { disableLogging(); }
gQueue.invoke(); // Will call SimpleTest.finish();
}

View File

@ -22,31 +22,98 @@
src="../browser.js"></script>
<script type="application/javascript">
function addTab(aURL)
////////////////////////////////////////////////////////////////////////////
// Invokers
function loadURIInvoker(aURI, aFunc)
{
this.invoke = function loadURIInvoker_invoke()
{
tabBrowser().loadURI(aURI);
}
this.eventSeq = [
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument)
];
this.finalCheck = function loadURIInvoker_finalCheck()
{
aFunc.call();
}
this.getID = function loadURIInvoker_getID()
{
return "load uri " + aURI;
}
}
function addTabInvoker(aURL, aFunc)
{
this.eventSeq = [
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
];
this.invoke = function addTab_invoke()
this.invoke = function addTabInvoker_invoke()
{
tabBrowser().loadOneTab(aURL, null, "", null, false);
}
this.finalCheck = function addTab_finalCheck()
this.finalCheck = function addTabInvoker_finalCheck()
{
var tabDoc = tabDocumentAt(0);
var input = getAccessible(tabDoc.getElementById("input"));
testStates(input, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
aFunc.call();
}
this.getID = function addTab_getID()
this.getID = function addTabInvoker_getID()
{
return "add tab: " + aURL;
}
}
var gInputDocURI = "data:text/html,<html><input id='input'></html>";
////////////////////////////////////////////////////////////////////////////
// Tests
function testBackgroundTab()
{
// Accessibles in background tab should have offscreen state and no
// invisible state.
var tabDoc = tabDocumentAt(0);
var input = getAccessible(tabDoc.getElementById("input"));
testStates(input, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
}
function testScrolledOff()
{
var tabDoc = tabDocumentAt(1);
// scrolled off
input = getAccessible(tabDoc.getElementById("input_scrolledoff"));
testStates(input, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
// scrolled off item (twice)
var lastLiNode = tabDoc.getElementById("li_last");
var lastLi = getAccessible(lastLiNode);
testStates(lastLi, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
// scroll into view the item
lastLiNode.scrollIntoView(true);
testStates(lastLi, 0, 0, STATE_OFFSCREEN | STATE_INVISIBLE);
// first item is scrolled off now (testcase for bug 768786)
var firstLi = getAccessible(tabDoc.getElementById("li_first"));
testStates(firstLi, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
}
var gInputDocURI = "data:text/html,<html><body>";
gInputDocURI += "<input id='input'></body></html>";
var gDocURI = "data:text/html,<html><body>";
gDocURI += "<div style='border:2px solid blue; width: 500px; height: 600px;'></div>";
gDocURI += "<input id='input_scrolledoff'>";
gDocURI += "<ul style='border:2px solid red; width: 100px; height: 50px; overflow: auto;'>";
gDocURI += " <li id='li_first'>item1</li><li>item2</li><li>item3</li>";
gDocURI += " <li>item4</li><li>item5</li><li id='li_last'>item6</li>";
gDocURI += "</ul>";
gDocURI += "</body></html>";
function doTests()
{
@ -56,16 +123,15 @@
gQueue = new eventQueue();
// Accessibles in background tab should have offscreen state and no
// invisible state.
gQueue.push(new addTab("about:blank"));
gQueue.push(new addTabInvoker("about:blank", testBackgroundTab));
gQueue.push(new loadURIInvoker(gDocURI, testScrolledOff));
gQueue.onFinish = function() { closeBrowserWindow(); }
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
openBrowserWindow(doTests, gInputDocURI);
openBrowserWindow(doTests, gInputDocURI, { width: 600, height: 600 });
</script>
</head>
@ -77,6 +143,11 @@
title="(in)visible state is not always correct?">
Mozilla Bug 591363
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=768786"
title="Offscreen state is not exposed under certain circumstances">
Mozilla Bug 768786
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">

View File

@ -77,11 +77,6 @@ var shell = {
if (Services.prefs.getBoolPref('app.reportCrashes') &&
crashID) {
if (!Services.io.offline) {
this.CrashSubmit.submit(crashID);
return;
}
Services.obs.addObserver(function observer(subject, topic, state) {
if (topic != "network:offline-status-changed")
return;
@ -114,6 +109,19 @@ var shell = {
},
start: function shell_start() {
// Dogfood id. We might want to remove it in the future.
// see bug 789466
try {
let dogfoodId = Services.prefs.getCharPref('prerelease.dogfood.id');
if (dogfoodId != "") {
let cr = Cc["@mozilla.org/xre/app-info;1"]
.getService(Ci.nsICrashReporter);
cr.annotateCrashReport("Email", dogfoodId);
}
}
catch (e) { }
let homeURL = this.homeURL;
if (!homeURL) {
let msg = 'Fatal error during startup: No homescreen found: try setting B2G_HOMESCREEN';
@ -432,6 +440,16 @@ Services.obs.addObserver(function onWebappsReady(subject, topic, data) {
shell.sendChromeEvent({ type: 'webapps-registry-ready' });
}, 'webapps-registry-ready', false);
Services.obs.addObserver(function onBluetoothVolumeChange(subject, topic, data) {
if (data == 'up') {
shell.sendChromeEvent({ type: 'volume-up-button-press' });
shell.sendChromeEvent({ type: 'volume-up-button-release' });
} else if (data == 'down') {
shell.sendChromeEvent({ type: 'volume-down-button-press' });
shell.sendChromeEvent({ type: 'volume-down-button-release' });
}
}, 'bluetooth-volume-change', false);
(function Repl() {
if (!Services.prefs.getBoolPref('b2g.remote-js.enabled')) {
return;

View File

@ -584,7 +584,6 @@ pref("plugins.hide_infobar_for_missing_plugin", false);
pref("plugins.hide_infobar_for_outdated_plugin", false);
#ifdef XP_MACOSX
pref("plugins.use_layers", true);
pref("plugins.hide_infobar_for_carbon_failure_plugin", false);
#endif
@ -1183,5 +1182,6 @@ pref("social.manifest.motown", "{\"origin\":\"https://motown-dev.mozillalabs.com
pref("social.activation.whitelist", "https://motown-dev.mozillalabs.com");
pref("social.sidebar.open", true);
pref("social.active", false);
pref("social.toast-notifications.enabled", true);
pref("dom.identity.enabled", false);

View File

@ -54,7 +54,7 @@
</div>
<div class="spacer"/>
<div id="launcher" session="true">
<div id="launcher">
<button class="launchButton" id="downloads">&abouthome.downloadsButton.label;</button>
<button class="launchButton" id="bookmarks">&abouthome.bookmarksButton.label;</button>
<button class="launchButton" id="history">&abouthome.historyButton.label;</button>

View File

@ -109,6 +109,7 @@
<command id="Social:SharePage" oncommand="SocialShareButton.sharePage();"/>
<command id="Social:UnsharePage" oncommand="SocialShareButton.unsharePage();"/>
<command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();"/>
<command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();"/>
<command id="Social:Toggle" oncommand="Social.toggle();" hidden="true"/>
</commandset>

View File

@ -10,6 +10,7 @@ let SocialUI = {
Services.obs.addObserver(this, "social:profile-changed", false);
Services.prefs.addObserver("social.sidebar.open", this, false);
Services.prefs.addObserver("social.toast-notifications.enabled", this, false);
gBrowser.addEventListener("ActivateSocialFeature", this._activationEventHandler, true, true);
@ -23,6 +24,7 @@ let SocialUI = {
Services.obs.removeObserver(this, "social:profile-changed");
Services.prefs.removeObserver("social.sidebar.open", this);
Services.prefs.removeObserver("social.toast-notifications.enabled", this);
},
showProfile: function SocialUI_showProfile() {
@ -57,6 +59,7 @@ let SocialUI = {
break;
case "nsPref:changed":
SocialSidebar.updateSidebar();
SocialToolbar.updateButton();
}
},
@ -589,6 +592,9 @@ var SocialToolbar = {
let notificationFrames = document.createDocumentFragment();
let iconContainers = document.createDocumentFragment();
let command = document.getElementById("Social:ToggleNotifications");
command.setAttribute("checked", Services.prefs.getBoolPref("social.toast-notifications.enabled"));
for each(let name in iconNames) {
let icon = provider.ambientNotificationIcons[name];

View File

@ -2493,8 +2493,8 @@ function BrowserOnAboutPageLoad(document) {
let ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
getService(Components.interfaces.nsISessionStore);
if (!ss.canRestoreLastSession)
document.getElementById("launcher").removeAttribute("session");
if (ss.canRestoreLastSession)
document.getElementById("launcher").setAttribute("session", "true");
// Inject search engine and snippets URL.
let docElt = document.documentElement;

View File

@ -684,6 +684,12 @@
command="Social:ToggleSidebar"
label="&social.toggleSidebar.label;"
accesskey="&social.toggleSidebar.accesskey;"/>
<menuitem id="social-toggle-notifications-menuitem"
type="checkbox"
autocheck="false"
command="Social:ToggleNotifications"
label="&social.toggleNotifications.label;"
accesskey="&social.toggleNotifications.accesskey;"/>
</menupopup>
</button>
<hbox id="social-status-iconbox" flex="1">

View File

@ -7,7 +7,7 @@
<binding id="chatbox">
<content orient="vertical" mousethrough="never">
<xul:hbox class="chat-titlebar" xbl:inherits="minimized,selected"
<xul:hbox class="chat-titlebar" xbl:inherits="minimized,selected,activity"
onclick="document.getBindingParent(this).toggle();" align="baseline">
<xul:image class="chat-status-icon" xbl:inherits="src=image"/>
<xul:label class="chat-title" flex="1" xbl:inherits="value=label,crop"/>
@ -78,11 +78,25 @@
<handler event="focus" phase="capturing">
this.parentNode.selectedChat = this;
</handler>
<handler event="load"><![CDATA[
<handler event="DOMContentLoaded"><![CDATA[
this.isActive = !this.minimized;
if (this._callback) this._callback(this.iframe.contentWindow);
let chatbox = this;
function chatActivity() {
chatbox.setAttribute("activity", true);
chatbox.parentNode.updateTitlebar(chatbox);
};
let iframeWindow = this.iframe.contentWindow;
iframeWindow.addEventListener("socialChatActivity", chatActivity);
iframeWindow.addEventListener("unload", function unload() {
iframeWindow.removeEventListener("unload", unload);
iframeWindow.removeEventListener("socialChatActivity", chatActivity);
});
]]></handler>
<handler event="DOMTitleChanged"><![CDATA[
this.setAttribute('label', this.iframe.contentDocument.title);
this.parentNode.updateTitlebar(this);
]]></handler>
<handler event="DOMTitleChanged" action="this.setAttribute('label', this.iframe.contentDocument.title);"/>
<handler event="DOMLinkAdded"><![CDATA[
// much of this logic is from DOMLinkHandler in browser.js
// this sets the presence icon for a chat user, we simply use favicon style updating
@ -99,6 +113,7 @@
// we made it this far, use it
this.setAttribute('image', uri.spec);
this.parentNode.updateTitlebar(this);
]]></handler>
</handlers>
</binding>
@ -124,6 +139,10 @@
document.getAnonymousElementByAttribute(this, "anonid", "nubMenu");
</field>
<field name="nub" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "nub");
</field>
<property name="emptyWidth">
<getter>
return document.getAnonymousElementByAttribute(this, "anonid", "spacer").boxObject.width;
@ -140,6 +159,7 @@
this._selectedChat = val;
if (val) {
this._selectedChat.setAttribute("selected", "true");
this._selectedChat.removeAttribute("activity");
}
]]></setter>
</property>
@ -196,6 +216,21 @@
]]></body>
</method>
<method name="updateTitlebar">
<parameter name="aChatbox"/>
<body><![CDATA[
if (aChatbox.collapsed) {
let menuitem = this.menuitemMap.get(aChatbox);
if (aChatbox.getAttribute("activity")) {
menuitem.setAttribute("activity", true);
this.nub.setAttribute("activity", true);
}
menuitem.setAttribute("label", aChatbox.getAttribute("label"));
menuitem.setAttribute("image", aChatbox.getAttribute("image"));
}
]]></body>
</method>
<method name="handleEvent">
<parameter name="aEvent"/>
<body><![CDATA[
@ -225,7 +260,9 @@
aChatbox.collapsed = true;
aChatbox.isActive = false;
let menu = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
menu.setAttribute("class", "menuitem-iconic");
menu.setAttribute("label", aChatbox.iframe.contentDocument.title);
menu.setAttribute("image", aChatbox.getAttribute("image"));
menu.chat = aChatbox;
this.menuitemMap.set(aChatbox, menu);
this.menupopup.appendChild(menu);
@ -296,6 +333,9 @@
</implementation>
<handlers>
<handler event="popupshown"><![CDATA[
this.nub.removeAttribute("activity");
]]></handler>
<handler event="overflow"><![CDATA[
// make sure we're not getting an overflow from content
if (event.originalTarget != this.innerbox)

View File

@ -651,5 +651,8 @@ toolbar button -->
<!ENTITY social.toggleSidebar.label "Show sidebar">
<!ENTITY social.toggleSidebar.accesskey "s">
<!ENTITY social.toggleNotifications.label "Show desktop notifications">
<!ENTITY social.toggleNotifications.accesskey "n">
<!ENTITY social.activated.undobutton.label "Undo">
<!ENTITY social.activated.undobutton.accesskey "U">

View File

@ -62,6 +62,11 @@ let Social = {
Services.prefs.setBoolPref("social.sidebar.open", !prefValue);
},
toggleNotifications: function SocialNotifications_toggle() {
let prefValue = Services.prefs.getBoolPref("social.toast-notifications.enabled");
Services.prefs.setBoolPref("social.toast-notifications.enabled", !prefValue);
},
// Sharing functionality
_getShareablePageUrl: function Social_getShareablePageUrl(aURI) {
let uri = aURI.clone();

View File

@ -2780,6 +2780,10 @@ html|*#gcli-output-frame {
background-color: #f0f0f0;
}
.chat-titlebar[activity] {
background-color: #ceeaff;
}
.chat-frame {
padding: 0;
margin: 0;
@ -2809,6 +2813,14 @@ html|*#gcli-output-frame {
display: none;
}
.chatbar-button[activity] {
background-color: #ceeaff;
}
.chatbar-button > menupopup > menuitem[activity] {
font-weight: bold;
}
.chatbar-innerbox {
background: transparent;
margin: -285px -1px 0 -1px;

View File

@ -3462,6 +3462,10 @@ html|*#gcli-output-frame {
border-bottom: none;
}
.chat-titlebar[activity] {
background-color: #ceeaff;
}
.chat-titlebar[selected] {
background-color: #f0f0f0;
}
@ -3495,6 +3499,14 @@ html|*#gcli-output-frame {
display: none;
}
.chatbar-button[activity] {
background-color: #ceeaff;
}
.chatbar-button > menupopup > menuitem[activity] {
font-weight: bold;
}
.chatbar-innerbox {
background: transparent;
margin: -285px -1px 0 -1px;

View File

@ -3484,6 +3484,10 @@ html|*#gcli-output-frame {
background-color: #dae3f0;
}
.chat-titlebar[activity] {
background-color: #ceeaff;
}
.chat-frame {
padding: 0;
margin: 0;
@ -3522,6 +3526,14 @@ html|*#gcli-output-frame {
display: none;
}
.chatbar-button[activity] {
background-color: #ceeaff;
}
.chatbar-button > menupopup > menuitem[activity] {
font-weight: bold;
}
.chatbar-innerbox {
background: transparent;
margin: -285px -1px 0 -1px;

View File

@ -65,7 +65,7 @@ PYTHON_VERSION_MAJOR=2
PYTHON_VERSION_MINOR=5
CAIRO_VERSION=1.10
PANGO_VERSION=1.14.0
GTK2_VERSION=2.18.0
GTK2_VERSION=2.10.0
WINDRES_VERSION=2.14.90
W32API_VERSION=3.14
GNOMEVFS_VERSION=2.0

View File

@ -1,51 +0,0 @@
/* 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 nsBlobProtocolHandler_h
#define nsBlobProtocolHandler_h
#include "nsIProtocolHandler.h"
#include "nsIURI.h"
#include "nsCOMPtr.h"
#define BLOBURI_SCHEME "blob"
class nsIDOMBlob;
class nsIPrincipal;
class nsIInputStream;
inline bool IsBlobURI(nsIURI* aUri)
{
bool isBlob;
return NS_SUCCEEDED(aUri->SchemeIs(BLOBURI_SCHEME, &isBlob)) && isBlob;
}
extern nsresult
NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
class nsBlobProtocolHandler : public nsIProtocolHandler
{
public:
NS_DECL_ISUPPORTS
// nsIProtocolHandler methods:
NS_DECL_NSIPROTOCOLHANDLER
// nsBlobProtocolHandler methods:
nsBlobProtocolHandler() {}
virtual ~nsBlobProtocolHandler() {}
// Methods for managing uri->file mapping
static void AddFileDataEntry(nsACString& aUri,
nsIDOMBlob* aFile,
nsIPrincipal* aPrincipal);
static void RemoveFileDataEntry(nsACString& aUri);
static nsIPrincipal* GetFileDataEntryPrincipal(nsACString& aUri);
};
#define NS_BLOBPROTOCOLHANDLER_CID \
{ 0xb43964aa, 0xa078, 0x44b2, \
{ 0xb0, 0x6b, 0xfd, 0x4d, 0x1b, 0x17, 0x2e, 0x66 } }
#endif /* nsBlobProtocolHandler_h */

View File

@ -34,7 +34,13 @@ let AppsUtils = {
removable: aApp.removable,
localId: aApp.localId,
progress: aApp.progress || 0.0,
status: aApp.status || "installed"
installState: aApp.installState || "installed",
downloadAvailable: aApp.downloadAvailable,
downloading: aApp.downloading,
readyToApplyDownload: aApp.readyToApplyDownload,
downloadSize: aApp.downloadSize || 0,
lastUpdateCheck: aApp.lastUpdateCheck,
etag: aApp.etag
};
},

View File

@ -12,6 +12,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
Cu.import("resource://gre/modules/ObjectWrapper.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
@ -54,7 +55,6 @@ WebappsRegistry.prototype = {
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
break;
case "Webapps:Install:Return:KO":
dump("XxXxX Webapps:Install:Return:KO\n");
Services.DOMRequest.fireError(req, msg.error || "DENIED");
break;
case "Webapps:GetSelf:Return:OK":
@ -120,10 +120,12 @@ WebappsRegistry.prototype = {
} else {
let receipts = (aParams && aParams.receipts && Array.isArray(aParams.receipts)) ? aParams.receipts : [];
let categories = (aParams && aParams.categories && Array.isArray(aParams.categories)) ? aParams.categories : [];
let etag = xhr.getResponseHeader("Etag");
cpmm.sendAsyncMessage("Webapps:Install", { app: { installOrigin: installOrigin,
origin: this._getOrigin(aURL),
manifestURL: aURL,
manifest: manifest,
etag: etag,
receipts: receipts,
categories: categories },
from: installURL,
@ -258,6 +260,36 @@ WebappsRegistry.prototype = {
classDescription: "Webapps Registry"})
}
/**
* nsIDOMDOMError object
*/
function createDOMError(aError) {
let error = Cc["@mozilla.org/dom-error;1"]
.createInstance(Ci.nsIDOMDOMError);
error.wrappedJSObject.init(aError);
return error;
}
function DOMError() {
this.wrappedJSObject = this;
}
DOMError.prototype = {
init: function domerror_init(aError) {
this.name = aError;
},
classID: Components.ID("{dcc1d5b7-43d8-4740-9244-b3d8db0f503d}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMDOMError]),
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{dcc1d5b7-43d8-4740-9244-b3d8db0f503d}"),
contractID: "@mozilla.org/dom-error;1",
interfaces: [Ci.nsIDOMDOMError],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "DOMError object"})
}
/**
* mozIDOMApplication object
*/
@ -278,17 +310,35 @@ WebappsApplication.prototype = {
init: function(aWindow, aApp) {
this.origin = aApp.origin;
this.manifest = ObjectWrapper.wrap(aApp.manifest, aWindow);
this.updateManifest = aApp.updateManifest ? ObjectWrapper.wrap(aApp.updateManifest, aWindow)
: null;
this.manifestURL = aApp.manifestURL;
this.receipts = aApp.receipts;
this.installOrigin = aApp.installOrigin;
this.installTime = aApp.installTime;
this.status = "installed";
this.installState = aApp.installState || "installed";
this.removable = aApp.removable;
this.lastUpdateCheck = aApp.lastUpdateCheck ? aApp.lastUpdateCheck
: Date.now();
this.progress = NaN;
this.downloadAvailable = aApp.downloadAvailable;
this.downloading = aApp.downloading;
this.readyToApplyDownload = aApp.readyToApplyDownload;
this.downloadSize = aApp.downloadSize || 0;
this._onprogress = null;
this._ondownloadsuccess = null;
this._ondownloaderror = null;
this._ondownloadavailable = null;
this._ondownloadapplied = null;
this._downloadError = null;
this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK",
"Webapps:Uninstall:Return:KO",
"Webapps:OfflineCache"]);
"Webapps:OfflineCache",
"Webapps:CheckForUpdate:Return:OK",
"Webapps:CheckForUpdate:Return:KO"]);
cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
["Webapps:Uninstall:Return:OK", "Webapps:OfflineCache"]);
},
@ -301,6 +351,60 @@ WebappsApplication.prototype = {
return this._onprogress;
},
set ondownloadsuccess(aCallback) {
this._ondownloadsuccess = aCallback;
},
get ondownloadsuccess() {
return this._ondownloadsuccess;
},
set ondownloaderror(aCallback) {
this._ondownloaderror = aCallback;
},
get ondownloaderror() {
return this._ondownloaderror;
},
set ondownloadavailable(aCallback) {
this._ondownloadavailable = aCallback;
},
get ondownloadavailable() {
return this._ondownloadavailable;
},
set ondownloadapplied(aCallback) {
this._ondownloadapplied = aCallback;
},
get ondownloadapplied() {
return this._ondownloadapplied;
},
get downloadError() {
return createDOMError(this._downloadError);
},
download: function() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
cancelDownload: function() {
cpmm.sendAsyncMessage("Webapps:CancelDownload",
{ manifestURL: this.manifestURL });
},
checkForUpdate: function() {
let request = this.createRequest();
cpmm.sendAsyncMessage("Webapps:CheckForUpdate",
{ manifestURL: this.manifestURL,
oid: this._id,
requestID: this.getRequestId(request) });
return request;
},
launch: function(aStartPoint) {
let request = this.createRequest();
cpmm.sendAsyncMessage("Webapps:Launch", { origin: this.origin,
@ -319,12 +423,27 @@ WebappsApplication.prototype = {
return request;
},
clearBrowserData: function() {
let browserChild =
BrowserElementPromptService.getBrowserElementChildForWindow(this._window);
if (browserChild) {
browserChild.messageManager.sendAsyncMessage("Webapps:ClearBrowserData");
}
},
uninit: function() {
this._onprogress = null;
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
["Webapps:Uninstall:Return:OK", "Webapps:OfflineCache"]);
},
_fireEvent: function(aName, aHandler) {
if (aHandler) {
let event = new this._window.MozApplicationEvent(aName, { application: this });
aHandler.handleEvent(event);
}
},
receiveMessage: function(aMessage) {
var msg = aMessage.json;
let req = this.takeRequest(msg.requestID);
@ -337,16 +456,41 @@ WebappsApplication.prototype = {
case "Webapps:Uninstall:Return:KO":
Services.DOMRequest.fireError(req, "NOT_INSTALLED");
break;
case "Webapps:Launch:Return:KO":
Services.DOMRequest.fireError(req, "APP_INSTALL_PENDING");
break;
case "Webapps:Uninstall:Return:KO":
Services.DOMRequest.fireError(req, "NOT_INSTALLED");
break;
case "Webapps:OfflineCache":
if (msg.manifest != this.manifestURL)
return;
this.status = msg.status;
if (this._onprogress) {
let event = new this._window.MozApplicationEvent("applicationinstall", { application: this });
this._onprogress.handleEvent(event);
if (installState in msg) {
this.installState = msg.installState;
if (this.installState == "installed") {
this._fireEvent("downloadsuccess", this._ondownloadsuccess);
this._fireEvent("downloadapplied", this._ondownloadapplied);
} else {
this._fireEvent("downloadprogress", this._onprogress);
}
} else if (msg.error) {
this._downloadError = msg.error;
this._fireEvent("downloaderror", this._ondownloaderror);
}
break;
case "Webapps:CheckForUpdate:Return:OK":
for (let prop in msg.app) {
this[prop] = msg.app[prop];
if (msg.event == "downloadapplied") {
Services.DOMRequest.fireSuccess(req, this.manifestURL);
this._fireEvent("downloadapplied", this._ondownloadapplied);
}
}
break;
case "Webapps:CheckForUpdate:Return:KO":
Services.DOMRequest.fireError(req, msg.error);
break;
}
},
@ -389,10 +533,11 @@ function WebappsApplicationMgmt(aWindow) {
WebappsApplicationMgmt.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
__exposedProps__: {
getAll: 'r',
getNotInstalled: 'r',
oninstall: 'rw',
onuninstall: 'rw'
applyDownload: "r",
getAll: "r",
getNotInstalled: "r",
oninstall: "rw",
onuninstall: "rw"
},
uninit: function() {
@ -402,6 +547,10 @@ WebappsApplicationMgmt.prototype = {
["Webapps:Install:Return:OK", "Webapps:Uninstall:Return:OK"]);
},
applyDownload: function(aApp) {
return Cr.NS_ERROR_NOT_IMPLEMENTED;
},
getAll: function() {
let request = this.createRequest();
cpmm.sendAsyncMessage("Webapps:GetAll", { oid: this._id,
@ -487,4 +636,6 @@ WebappsApplicationMgmt.prototype = {
classDescription: "Webapps Application Mgmt"})
}
const NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry, WebappsApplication]);
const NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry,
WebappsApplication,
DOMError]);

View File

@ -17,6 +17,10 @@ Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import('resource://gre/modules/ActivitiesService.jsm');
Cu.import("resource://gre/modules/AppsUtils.jsm");
function debug(aMsg) {
//dump("-*-*- Webapps.jsm : " + aMsg + "\n");
}
const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
@ -61,7 +65,10 @@ let DOMApplicationRegistry = {
"Webapps:Launch", "Webapps:GetAll",
"Webapps:InstallPackage", "Webapps:GetBasePath",
"Webapps:GetList", "Webapps:RegisterForMessages",
"Webapps:UnregisterForMessages"];
"Webapps:UnregisterForMessages",
"Webapps:CancelDownload", "Webapps:CheckForUpdate"];
this.frameMessages = ["Webapps:ClearBrowserData"];
this.messages.forEach((function(msgName) {
ppmm.addMessageListener(msgName, this);
@ -445,7 +452,7 @@ let DOMApplicationRegistry = {
this.uninstall(msg);
break;
case "Webapps:Launch":
Services.obs.notifyObservers(mm, "webapps-launch", JSON.stringify(msg));
this.launchApp(msg, mm);
break;
case "Webapps:IsInstalled":
this.isInstalled(msg, mm);
@ -477,6 +484,12 @@ let DOMApplicationRegistry = {
case "Webapps:GetList":
this.addMessageListener(["Webapps:AddApp", "Webapps:RemoveApp"], mm);
return this.webapps;
case "Webapps:CancelDownload":
this.cancelDowload(msg.manifestURL);
break;
case "Webapps:CheckForUpdate":
this.checkForUpdate(msg, mm);
break;
case "Activities:Register:OK":
this.activitiesRegistered++;
if (this.allActivitiesSent &&
@ -534,6 +547,157 @@ let DOMApplicationRegistry = {
});
},
launchApp: function launchApp(aData, aMm) {
let app = this.getAppByManifestURL(aData.manifestURL);
if (!app) {
aMm.sendAsyncMessage("Webapps:Launch:Return:KO", aData);
return;
}
// Fire an error when trying to launch an app that is not
// yet fully installed.
if (app.installState == "pending") {
aMm.sendAsyncMessage("Webapps:Launch:Return:KO", aData);
return;
}
Services.obs.notifyObservers(aMm, "webapps-launch", JSON.stringify(aData));
},
cancelDownload: function cancelDowload(aManifestURL) {
// We can't cancel appcache dowloads for now.
},
startOfflineCacheDownload: function startOfflineCacheDownload(aManifest, aApp, aProfileDir) {
// if the manifest has an appcache_path property, use it to populate the appcache
if (aManifest.appcache_path) {
let appcacheURI = Services.io.newURI(aManifest.fullAppcachePath(), null, null);
let updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]
.getService(Ci.nsIOfflineCacheUpdateService);
let docURI = Services.io.newURI(aManifest.fullLaunchPath(), null, null);
let cacheUpdate = aProfileDir ? updateService.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
: updateService.scheduleUpdate(appcacheURI, docURI, null);
cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
if (aOfflineCacheObserver) {
cacheUpdate.addObserver(aOfflineCacheObserver, false);
}
}
},
checkForUpdate: function(aData, aMm) {
let app = this.getAppByManifestURL(aData.manifestURL);
if (!app) {
aData.error = "NO_SUCH_APP";
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
return;
}
function sendError(aError) {
aData.error = aError;
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
}
function updatePackagedApp(aManifest) {
debug("updatePackagedApp");
}
function updateHostedApp(aManifest) {
debug("updateHostedApp");
let id = this._appId(app.origin);
#ifdef MOZ_SYS_MSG
// Update the Web Activities
this._readManifests([{ id: id }], (function unregisterManifest(aResult) {
this._unregisterActivities(aResult[0].manifest, app);
this._registerSystemMessages(aManifest, app);
this._registerActivities(aManifest, app);
}).bind(this));
#endif
// Store the new manifest.
let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
let manFile = dir.clone();
manFile.append("manifest.webapp");
this._writeFile(manFile, JSON.stringify(aManifest), function() { });
let manifest = new DOMApplicationManifest(aManifest, app.origin);
if (manifest.appcache_path) {
app.installState = "updating";
app.downloadAvailable = true;
app.downloading = true;
app.downloadsize = 0;
app.readyToApplyDownload = false;
} else {
app.installState = "installed";
app.downloadAvailable = false;
app.downloading = false;
app.readyToApplyDownload = false;
}
app.name = aManifest.name;
// Update the registry.
this.webapps[id] = app;
this._saveApps((function() {
// XXX Should we fire notifications ?
}).bind(this));
// Preload the appcache if needed.
this.startOfflineCacheDownload(manifest, app);
}
// First, we download the manifest.
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
xhr.open("GET", aData.manifestURL, true);
if (aData.etag) {
xhr.setRequestHeader("If-None-Match", aData.etag);
}
xhr.addEventListener("load", (function() {
if (xhr.status == 200) {
let manifest;
try {
JSON.parse(xhr.responseText, installOrigin);
} catch(e) {
sendError("MANIFEST_PARSE_ERROR");
return;
}
if (!AppsUtils.checkManifest(manifest, installOrigin)) {
sendError("INVALID_MANIFEST");
} else {
app.etag = xhr.getResponseHeader("Etag");
app.lastCheckedUpdate = Date.now();
if (package_path in manifest) {
updatePackagedApp(manifest);
} else {
updateHostedApp(manifest);
}
}
this._saveApps();
} else if (xhr.status == 304) {
// The manifest has not changed. We just update lastCheckedUpdate.
app.lastCheckedUpdate = Date.now();
aData.event = "downloadapplied";
aData.app = {
lastCheckedUpdate: app.lastCheckedUpdate
}
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
this._saveApps();
} else {
sendError("MANIFEST_URL_ERROR");
}
}).bind(this), false);
xhr.addEventListener("error", (function() {
sendError(request, "NETWORK_ERROR");
}).bind(this), false);
xhr.send(null);
},
denyInstall: function(aData) {
let packageId = aData.app.packageId;
if (packageId) {
@ -573,6 +737,7 @@ let DOMApplicationRegistry = {
let appObject = AppsUtils.cloneAppObject(app);
appObject.appStatus = app.appStatus || Ci.nsIPrincipal.APP_STATUS_INSTALLED;
appObject.installTime = app.installTime = Date.now();
appObject.lastUpdateCheck = app.lastUpdateCheck = Date.now();
let appNote = JSON.stringify(appObject);
appNote.id = id;
@ -597,13 +762,26 @@ let DOMApplicationRegistry = {
}
}
});
this.webapps[id] = appObject;
appObject.status = "installed";
appObject.name = app.manifest.name;
let manifest = new DOMApplicationManifest(app.manifest, app.origin);
if (manifest.appcache_path) {
appObject.installState = "pending";
appObject.downloadAvailable = true;
appObject.downloading = true;
appObject.downloadsize = 0;
appObject.readyToApplyDownload = false;
} else {
appObject.installState = "installed";
appObject.downloadAvailable = false;
appObject.downloading = false;
appObject.readyToApplyDownload = false;
}
appObject.name = app.manifest.name;
this.webapps[id] = appObject;
if (!aFromSync)
this._saveApps((function() {
this.broadcastMessage("Webapps:Install:Return:OK", aData);
@ -616,19 +794,7 @@ let DOMApplicationRegistry = {
this._registerActivities(app.manifest, app);
#endif
// if the manifest has an appcache_path property, use it to populate the appcache
if (manifest.appcache_path) {
let appcacheURI = Services.io.newURI(manifest.fullAppcachePath(), null, null);
let updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]
.getService(Ci.nsIOfflineCacheUpdateService);
let docURI = Services.io.newURI(manifest.fullLaunchPath(), null, null);
let cacheUpdate = aProfileDir ? updateService.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
: updateService.scheduleUpdate(appcacheURI, docURI, null);
cacheUpdate.addObserver(new AppcacheObserver(appObject), false);
if (aOfflineCacheObserver) {
cacheUpdate.addObserver(aOfflineCacheObserver, false);
}
}
this.startOfflineCacheDownload(manifest, appObject, aProfileDir);
},
_nextLocalId: function() {
@ -651,7 +817,7 @@ let DOMApplicationRegistry = {
},
_saveApps: function(aCallback) {
this._writeFile(this.appsFile, JSON.stringify(this.webapps), function() {
this._writeFile(this.appsFile, JSON.stringify(this.webapps, null, 2), function() {
if (aCallback)
aCallback();
});
@ -842,11 +1008,11 @@ let DOMApplicationRegistry = {
let appNote = JSON.stringify(AppsUtils.cloneAppObject(app));
appNote.id = id;
this._readManifests([{ id: id }], (function unregisterManifest(aResult) {
#ifdef MOZ_SYS_MSG
this._readManifests([{ id: id }], (function unregisterManifest(aResult) {
this._unregisterActivities(aResult[0].manifest, app);
#endif
}).bind(this));
#endif
let dir = this._getAppDir(id);
try {
@ -1136,6 +1302,79 @@ let DOMApplicationRegistry = {
return true;
#endif
},
_notifyCategoryAndObservers: function(subject, topic, data) {
const serviceMarker = "service,";
// First create observers from the category manager.
let cm =
Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
let enumerator = cm.enumerateCategory(topic);
let observers = [];
while (enumerator.hasMoreElements()) {
let entry =
enumerator.getNext().QueryInterface(Ci.nsISupportsCString).data;
let contractID = cm.getCategoryEntry(topic, entry);
let factoryFunction;
if (contractID.substring(0, serviceMarker.length) == serviceMarker) {
contractID = contractID.substring(serviceMarker.length);
factoryFunction = "getService";
}
else {
factoryFunction = "createInstance";
}
try {
let handler = Cc[contractID][factoryFunction]();
if (handler) {
let observer = handler.QueryInterface(Ci.nsIObserver);
observers.push(observer);
}
} catch(e) { }
}
// Next enumerate the registered observers.
enumerator = Services.obs.enumerateObservers(topic);
while (enumerator.hasMoreElements()) {
let observer = enumerator.getNext();
if (observers.indexOf(observer) == -1) {
observers.push(observer);
}
}
observers.forEach(function (observer) {
try {
observer.observe(subject, topic, data);
} catch(e) { }
});
},
registerBrowserElementParentForApp: function(bep, appId) {
let mm = bep._mm;
// Make a listener function that holds on to this appId.
let listener = this.receiveAppMessage.bind(this, appId);
this.frameMessages.forEach(function(msgName) {
mm.addMessageListener(msgName, listener);
});
},
receiveAppMessage: function(appId, message) {
switch (message.name) {
case "Webapps:ClearBrowserData":
let subject = {
appId: appId,
browserOnly: true,
QueryInterface: XPCOMUtils.generateQI([Ci.mozIApplicationClearPrivateDataParams])
};
this._notifyCategoryAndObservers(subject, "webapps-clear-data", null);
break;
}
}
};
@ -1144,6 +1383,7 @@ let DOMApplicationRegistry = {
*/
let AppcacheObserver = function(aApp) {
this.app = aApp;
this.startStatus = aApp.installState;
};
AppcacheObserver.prototype = {
@ -1153,27 +1393,33 @@ AppcacheObserver.prototype = {
let app = this.app;
let setStatus = function appObs_setStatus(aStatus) {
mustSave = (app.status != aStatus);
app.status = aStatus;
mustSave = (app.installState != aStatus);
app.installState = aStatus;
DOMApplicationRegistry.broadcastMessage("Webapps:OfflineCache",
{ manifest: app.manifestURL,
status: aStatus });
installState: app.installState });
}
let setError = function appObs_setError(aError) {
DOMApplicationRegistry.broadcastMessage("Webapps:OfflineCache",
{ manifest: app.manifestURL,
error: aError });
}
switch (aState) {
case Ci.nsIOfflineCacheUpdateObserver.STATE_ERROR:
aUpdate.removeObserver(this);
setStatus("cache-error");
setError("APP_CACHE_DOWNLOAD_ERROR");
break;
case Ci.nsIOfflineCacheUpdateObserver.STATE_NOUPDATE:
case Ci.nsIOfflineCacheUpdateObserver.STATE_FINISHED:
aUpdate.removeObserver(this);
setStatus("cached");
setStatus("installed");
break;
case Ci.nsIOfflineCacheUpdateObserver.STATE_DOWNLOADING:
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS:
setStatus("downloading")
setStatus(this.startStatus);
break;
}

View File

@ -5,3 +5,6 @@ category JavaScript-navigator-property mozApps @mozilla.org/webapps;1
component {723ed303-7757-4fb0-b261-4f78b1f6bd22} Webapps.js
contract @mozilla.org/webapps/application;1 {723ed303-7757-4fb0-b261-4f78b1f6bd22}
component {dcc1d5b7-43d8-4740-9244-b3d8db0f503d} Webapps.js
contract @mozilla.org/dom-error;1 {dcc1d5b7-43d8-4740-9244-b3d8db0f503d}

View File

@ -6,7 +6,7 @@
#include "nsISupports.idl"
[scriptable, builtinclass, uuid(e4e28307-d409-4cf7-93cd-6ea8e889f87a)]
[scriptable, uuid(e4e28307-d409-4cf7-93cd-6ea8e889f87a)]
interface nsIDOMDOMError : nsISupports
{
readonly attribute DOMString name;

View File

@ -10,12 +10,15 @@
#include "BluetoothService.h"
#include "BluetoothServiceUuid.h"
#include "mozilla/Services.h"
#include "nsIObserverService.h"
USING_BLUETOOTH_NAMESPACE
using namespace mozilla::ipc;
static nsRefPtr<BluetoothHfpManager> sInstance = nullptr;
BluetoothHfpManager::BluetoothHfpManager()
BluetoothHfpManager::BluetoothHfpManager() : mCurrentVgs(-1)
{
}
@ -41,6 +44,79 @@ void
BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
{
MOZ_ASSERT(NS_IsMainThread());
const char* msg = (const char*)aMessage->mData;
// For more information, please refer to 4.34.1 "Bluetooth Defined AT
// Capabilities" in Bluetooth hands-free profile 1.6
if (!strncmp(msg, "AT+BRSF=", 8)) {
SendLine("+BRSF: 23");
SendLine("OK");
} else if (!strncmp(msg, "AT+CIND=?", 9)) {
nsAutoCString cindRange;
cindRange += "+CIND: ";
cindRange += "(\"battchg\",(0-5)),";
cindRange += "(\"signal\",(0-5)),";
cindRange += "(\"service\",(0,1)),";
cindRange += "(\"call\",(0,1)),";
cindRange += "(\"callsetup\",(0-3)),";
cindRange += "(\"callheld\",(0-2)),";
cindRange += "(\"roam\",(0,1))";
SendLine(cindRange.get());
SendLine("OK");
} else if (!strncmp(msg, "AT+CIND", 7)) {
// FIXME - Bug 794349
// This value reflects current status of telephony, roaming, battery ...,
// so obviously fixed value must be wrong if there is an ongoing call.
// Need a patch for this, but currently just using fixed value for basic
// SLC establishment.
SendLine("+CIND: 5,5,1,0,0,0,0");
SendLine("OK");
} else if (!strncmp(msg, "AT+CMER=", 8)) {
SendLine("OK");
} else if (!strncmp(msg, "AT+CHLD=?", 9)) {
SendLine("+CHLD: (0,1,2,3)");
SendLine("OK");
} else if (!strncmp(msg, "AT+CHLD=", 8)) {
SendLine("OK");
} else if (!strncmp(msg, "AT+VGS=", 7)) {
// VGS range: [0, 15]
int newVgs = msg[7] - '0';
if (strlen(msg) > 8) {
newVgs *= 10;
newVgs += (msg[8] - '0');
}
#ifdef DEBUG
NS_ASSERTION(newVgs >= 0 && newVgs <= 15, "Received invalid VGS value");
#endif
// Currently, we send volume up/down commands to represent that
// volume has been changed by Bluetooth headset, and that will affect
// the main stream volume of our device. In the future, we may want to
// be able to set volume by stream.
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (newVgs > mCurrentVgs) {
os->NotifyObservers(nullptr, "bluetooth-volume-change", NS_LITERAL_STRING("up").get());
} else if (newVgs < mCurrentVgs) {
os->NotifyObservers(nullptr, "bluetooth-volume-change", NS_LITERAL_STRING("down").get());
}
mCurrentVgs = newVgs;
SendLine("OK");
} else {
#ifdef DEBUG
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling HFP message, reply ok: ");
warningMsg.Append(msg);
NS_WARNING(warningMsg.get());
#endif
SendLine("OK");
}
}
bool
@ -78,3 +154,16 @@ BluetoothHfpManager::Disconnect()
CloseSocket();
}
bool
BluetoothHfpManager::SendLine(const char* aMessage)
{
const char* kHfpCrlf = "\xd\xa";
nsAutoCString msg;
msg += kHfpCrlf;
msg += aMessage;
msg += kHfpCrlf;
return SendSocketData(msg);
}

View File

@ -25,9 +25,12 @@ public:
bool Connect(const nsAString& aDeviceObjectPath,
BluetoothReplyRunnable* aRunnable);
void Disconnect();
bool SendLine(const char* aMessage);
private:
BluetoothHfpManager();
int mCurrentVgs;
};
END_BLUETOOTH_NAMESPACE

View File

@ -675,6 +675,18 @@ BrowserElementChild.prototype = {
onProgressChange: function(webProgress, request, curSelfProgress,
maxSelfProgress, curTotalProgress, maxTotalProgress) {},
},
// Expose the message manager for WebApps and others.
_messageManagerPublic: {
sendAsyncMessage: global.sendAsyncMessage.bind(global),
sendSyncMessage: global.sendSyncMessage.bind(global),
addMessageListener: global.addMessageListener.bind(global),
removeMessageListener: global.removeMessageListener.bind(global)
},
get messageManager() {
return this._messageManagerPublic;
}
};
var api = new BrowserElementChild();

View File

@ -13,6 +13,11 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
XPCOMUtils.defineLazyGetter(this, "DOMApplicationRegistry", function () {
Cu.import("resource://gre/modules/Webapps.jsm");
return DOMApplicationRegistry;
});
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
const BROWSER_FRAMES_ENABLED_PREF = "dom.mozBrowserFramesEnabled";
const TOUCH_EVENTS_ENABLED_PREF = "dom.w3c_touch_events.enabled";
@ -250,6 +255,18 @@ function BrowserElementParent(frameLoader, hasRemoteFrame) {
// Insert ourself into the prompt service.
BrowserElementPromptService.mapFrameToBrowserElementParent(this._frameElement, this);
// If this browser represents an app then let the Webapps module register for
// any messages that it needs.
let appManifestURL =
this._frameElement.QueryInterface(Ci.nsIMozBrowserFrame).appManifestURL;
if (appManifestURL) {
let appId =
DOMApplicationRegistry.getAppLocalIdByManifestURL(appManifestURL);
if (appId != Ci.nsIScriptSecurityManager.NO_APP_ID) {
DOMApplicationRegistry.registerBrowserElementParentForApp(this, appId);
}
}
}
BrowserElementParent.prototype = {

View File

@ -16,6 +16,7 @@ GRE_MODULE = 1
XPIDLSRCS = \
mozIApplication.idl \
mozIApplicationClearPrivateDataParams.idl \
nsIDOMApplicationRegistry.idl \
nsIDOMApplicationRegistry2.idl \
nsIAppsService.idl \

View File

@ -0,0 +1,15 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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/. */
#include "nsISupports.idl"
[scriptable, uuid(ba0e6c8e-8c03-4b9b-8f9b-4fb14216f56e)]
interface mozIApplicationClearPrivateDataParams
{
readonly attribute unsigned long appId;
readonly attribute boolean browserOnly;
};

View File

@ -6,12 +6,13 @@
#include "nsIDOMEventTarget.idl"
interface nsIDOMDOMRequest;
interface nsIArray;
interface nsIDOMDOMError;
[scriptable, uuid(e3649c1d-c950-495e-b0ed-6ce40be9743b)]
[scriptable, uuid(b00a5908-1228-46bf-a42b-091dce3abde1)]
interface mozIDOMApplication : nsISupports
{
readonly attribute jsval manifest;
readonly attribute jsval updateManifest;
readonly attribute DOMString manifestURL;
readonly attribute jsval receipts; /* an array of strings */
readonly attribute DOMString origin;
@ -19,31 +20,72 @@ interface mozIDOMApplication : nsISupports
readonly attribute unsigned long long installTime;
readonly attribute boolean removable;
/*
/**
* The current progress when downloading an offline cache.
*/
readonly attribute double progress;
/*
* The application status :
* "installed" : The app is in the registry, but we have no offline cache.
* "downlading" : We are downloading the offline cache.
* "cached" : We are done with the offline cache download.
* "cache-error" : An error occured while downloading the offline-cache.
/**
* The application installation state :
* "pending" : The application is being installed (eg, we're downloading the
* offline cache or the package).
* "installed" : The application is installed and ready to be launched.
* "updating" : We are updating the offline-cache or the package.
*/
readonly attribute DOMString status;
readonly attribute DOMString installState;
/*
* fires a nsIDOMApplicationEvent when a change in appcache download or status happens
/**
* fires a nsIDOMApplicationEvent when a change in appcache download or
* package download happens.
*/
attribute nsIDOMEventListener onprogress;
/**
* The date of the last update.
*/
readonly attribute unsigned long long lastUpdateCheck;
/**
* Starts the process of looking for an update.
*/
nsIDOMDOMRequest checkForUpdate();
readonly attribute boolean downloadAvailable;
readonly attribute boolean downloading;
readonly attribute boolean readyToApplyDownload;
readonly attribute long downloadSize;
readonly attribute nsIDOMDOMError downloadError;
attribute nsIDOMEventListener ondownloadsuccess;
attribute nsIDOMEventListener ondownloaderror;
attribute nsIDOMEventListener ondownloadavailable;
/**
* Will fire once the mgmt.applyDownload() call succeeds.
*/
attribute nsIDOMEventListener ondownloadapplied;
/**
* Starts to download an update. If |downloading| is true, this
* is a no-op.
*/
void download();
/**
* Cancels an ongoing update download.
*/
void cancelDownload();
/* startPoint will be used when several launch_path exists for an app */
nsIDOMDOMRequest launch([optional] in DOMString startPoint);
nsIDOMDOMRequest uninstall();
/* Clear data that has been collected through mozbrowser elements. */
void clearBrowserData();
};
[scriptable, uuid(4c36ca48-841e-4d5a-8c46-dda14ac633ca)]
[scriptable, uuid(0015d114-70c1-44ae-a8a3-fb6c107fe0e1)]
interface mozIDOMApplicationMgmt : nsISupports
{
/**
@ -71,6 +113,13 @@ interface mozIDOMApplicationMgmt : nsISupports
* the event will be a mozIDOMApplicationEvent
*/
attribute nsIDOMEventListener onuninstall;
/**
* Applies a downloaded update.
* This function is a no-op if it's passed an app object which doesn't have
* |readyToApplyDownload| set to true.
*/
void applyDownload(in mozIDOMApplication app);
};
[scriptable, uuid(7ca34d3e-d855-4d0a-a3b3-58c0acad9ec3)]

View File

@ -171,12 +171,7 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance()
mPlugin(nullptr),
mMIMEType(nullptr),
mOwner(nullptr),
mCurrentPluginEvent(nullptr),
#if defined(MOZ_X11) || defined(XP_WIN) || defined(XP_MACOSX)
mUsePluginLayersPref(true)
#else
mUsePluginLayersPref(false)
#endif
mCurrentPluginEvent(nullptr)
#ifdef MOZ_WIDGET_ANDROID
, mOnScreen(true)
#endif
@ -184,9 +179,6 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance()
mNPP.pdata = NULL;
mNPP.ndata = this;
mUsePluginLayersPref =
Preferences::GetBool("plugins.use_layers", mUsePluginLayersPref);
PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
}
@ -1212,13 +1204,8 @@ nsNPAPIPluginInstance::NotifyPainted(void)
}
nsresult
nsNPAPIPluginInstance::UseAsyncPainting(bool* aIsAsync)
nsNPAPIPluginInstance::GetIsOOP(bool* aIsAsync)
{
if (!mUsePluginLayersPref) {
*aIsAsync = mUsePluginLayersPref;
return NS_OK;
}
AutoPluginLibraryCall library(this);
if (!library)
return NS_ERROR_FAILURE;

View File

@ -84,7 +84,7 @@ public:
nsresult GetImageContainer(ImageContainer **aContainer);
nsresult GetImageSize(nsIntSize* aSize);
nsresult NotifyPainted(void);
nsresult UseAsyncPainting(bool* aIsAsync);
nsresult GetIsOOP(bool* aIsOOP);
nsresult SetBackgroundUnknown();
nsresult BeginUpdateBackground(nsIntRect* aRect, gfxContext** aContext);
nsresult EndUpdateBackground(gfxContext* aContext, nsIntRect* aRect);
@ -343,7 +343,6 @@ private:
// This is only valid when the plugin is actually stopped!
mozilla::TimeStamp mStopTime;
bool mUsePluginLayersPref;
#ifdef MOZ_WIDGET_ANDROID
void EnsureSharedTexture();
nsSurfaceTexture* CreateSurfaceTexture();

View File

@ -263,10 +263,9 @@ nsPluginInstanceOwner::UseAsyncRendering()
}
#endif
bool useAsyncRendering;
bool isOOP;
bool result = (mInstance &&
NS_SUCCEEDED(mInstance->UseAsyncPainting(&useAsyncRendering)) &&
useAsyncRendering
NS_SUCCEEDED(mInstance->GetIsOOP(&isOOP)) && isOOP
#ifndef XP_MACOSX
&& (!mPluginWindow ||
mPluginWindow->type == NPWindowTypeDrawable)

View File

@ -146,10 +146,6 @@ child:
returns (NPError rv);
parent:
rpc NPN_GetValue_NPNVjavascriptEnabledBool()
returns (bool value, NPError result);
rpc NPN_GetValue_NPNVisOfflineBool()
returns (bool value, NPError result);
rpc NPN_GetValue_NPNVWindowNPObject()
returns (nullable PPluginScriptableObject value, NPError result);
rpc NPN_GetValue_NPNVPluginElementNPObject()

View File

@ -287,14 +287,6 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
switch(aVar) {
case NPNVSupportsWindowless:
#if defined(OS_LINUX) || defined(MOZ_X11) || defined(OS_WIN)
*((NPBool*)aValue) = true;
#else
*((NPBool*)aValue) = false;
#endif
return NPERR_NO_ERROR;
#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
case NPNVSupportsWindowlessLocal: {
#ifdef MOZ_WIDGET_QT
@ -308,10 +300,6 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
}
#endif
#if defined(MOZ_X11)
case NPNVSupportsXEmbedBool:
*((NPBool*)aValue) = true;
return NPERR_NO_ERROR;
case NPNVToolkit:
*((NPNToolkitType*)aValue) = NPNVGtk2;
return NPERR_NO_ERROR;
@ -329,26 +317,6 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
case NPNVToolkit:
return NPERR_GENERIC_ERROR;
#endif
case NPNVjavascriptEnabledBool: {
bool v = false;
NPError result;
if (!CallNPN_GetValue_NPNVjavascriptEnabledBool(&v, &result)) {
return NPERR_GENERIC_ERROR;
}
*static_cast<NPBool*>(aValue) = v;
return result;
}
case NPNVisOfflineBool: {
bool v = false;
NPError result;
if (!CallNPN_GetValue_NPNVisOfflineBool(&v, &result)) {
return NPERR_GENERIC_ERROR;
}
*static_cast<NPBool*>(aValue) = v;
return result;
}
case NPNVprivateModeBool: {
bool v = false;
NPError result;
@ -468,6 +436,15 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
#endif /* NP_NO_QUICKDRAW */
#endif /* XP_MACOSX */
#ifdef DEBUG
case NPNVjavascriptEnabledBool:
case NPNVasdEnabledBool:
case NPNVisOfflineBool:
case NPNVSupportsXEmbedBool:
case NPNVSupportsWindowless:
NS_NOTREACHED("NPNVariable should be handled in PluginModuleChild.");
#endif
default:
PR_LOG(gPluginLog, PR_LOG_WARNING,
("In PluginInstanceChild::NPN_GetValue: Unhandled NPNVariable %i (%s)",

View File

@ -191,27 +191,6 @@ PluginInstanceParent::DeallocPPluginStream(PPluginStreamParent* stream)
return true;
}
bool
PluginInstanceParent::AnswerNPN_GetValue_NPNVjavascriptEnabledBool(
bool* value,
NPError* result)
{
NPBool v;
*result = mNPNIface->getvalue(mNPP, NPNVjavascriptEnabledBool, &v);
*value = v;
return true;
}
bool
PluginInstanceParent::AnswerNPN_GetValue_NPNVisOfflineBool(bool* value,
NPError* result)
{
NPBool v;
*result = mNPNIface->getvalue(mNPP, NPNVisOfflineBool, &v);
*value = v;
return true;
}
bool
PluginInstanceParent::AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle* value,
NPError* result)

View File

@ -88,10 +88,6 @@ public:
virtual bool
DeallocPPluginStream(PPluginStreamParent* stream);
virtual bool
AnswerNPN_GetValue_NPNVjavascriptEnabledBool(bool* value, NPError* result);
virtual bool
AnswerNPN_GetValue_NPNVisOfflineBool(bool* value, NPError* result);
virtual bool
AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle* value,
NPError* result);

View File

@ -36,6 +36,7 @@ for (var p in props) {
var mgmtProps = {
QueryInterface: "function",
applyDownload: "function",
getAll: "function",
getNotInstalled: "function",
oninstall: "object",

View File

@ -36,7 +36,8 @@ public:
ShmemYCbCrImage() : mOffset(0) {}
ShmemYCbCrImage(Shmem& shm, size_t offset = 0) {
NS_ABORT_IF_FALSE(Open(shm,offset), "Invalid data in Shmem.");
DebugOnly<bool> status = Open(shm,offset);
NS_ASSERTION(status, "Invalid data in the shmem");
}
/**

View File

@ -443,7 +443,7 @@ ReflowArgTypes(JSContext *cx)
{
StackFrame *fp = cx->fp();
unsigned nargs = fp->fun()->nargs;
JSScript *script = fp->script();
RootedScript script(cx, fp->script());
types::AutoEnterTypeInference enter(cx);
@ -467,7 +467,7 @@ ion::ReflowTypeInfo(uint32 bailoutResult)
return true;
}
JSScript *script = cx->fp()->script();
RootedScript script(cx, cx->fp()->script());
jsbytecode *pc = activation->bailout()->bailoutPc();
JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);

View File

@ -150,10 +150,10 @@ IonCompartment::initialize(JSContext *cx)
void
ion::FinishOffThreadBuilder(IonBuilder *builder)
{
if (builder->script->isIonCompilingOffThread()) {
types::TypeCompartment &types = builder->script->compartment()->types;
if (builder->script()->isIonCompilingOffThread()) {
types::TypeCompartment &types = builder->script()->compartment()->types;
builder->recompileInfo.compilerOutput(types)->invalidate();
builder->script->ion = NULL;
builder->script()->ion = NULL;
}
js_delete(builder->temp().lifoAlloc());
}
@ -903,17 +903,17 @@ class AutoDestroyAllocator
bool
TestCompiler(IonBuilder *builder, MIRGraph *graph, AutoDestroyAllocator &autoDestroy)
{
JS_ASSERT(!builder->script->ion);
JS_ASSERT(!builder->script()->ion);
JSContext *cx = GetIonContext()->cx;
IonSpewNewFunction(graph, builder->script);
IonSpewNewFunction(graph, builder->script());
if (!builder->build())
return false;
builder->clearForBackEnd();
if (js_IonOptions.parallelCompilation) {
builder->script->ion = ION_COMPILING_SCRIPT;
builder->script()->ion = ION_COMPILING_SCRIPT;
if (!StartOffThreadIonCompile(cx, builder))
return false;
@ -955,7 +955,7 @@ AttachFinishedCompilations(JSContext *cx)
IonBuilder *builder = compilations.popCopy();
if (builder->lir) {
JSScript *script = builder->script;
JSScript *script = builder->script();
IonContext ictx(cx, cx->compartment, &builder->temp());
CodeGenerator codegen(builder, *builder->lir);

View File

@ -26,7 +26,6 @@ using namespace js::ion;
IonBuilder::IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
TypeOracle *oracle, CompileInfo *info, size_t inliningDepth, uint32 loopDepth)
: MIRGenerator(cx->compartment, temp, graph, info),
script(info->script()),
recompileInfo(cx->compartment->types.compiledInfo),
lir(NULL),
cx(cx),
@ -35,9 +34,10 @@ IonBuilder::IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
callerBuilder_(NULL),
oracle(oracle),
inliningDepth(inliningDepth),
failedBoundsCheck_(script->failedBoundsCheck),
failedBoundsCheck_(info->script()->failedBoundsCheck),
lazyArguments_(NULL)
{
script_.init(info->script());
pc = info->startPC();
}
@ -57,7 +57,7 @@ IonBuilder::abort(const char *message, ...)
va_start(ap, message);
abortFmt(message, ap);
va_end(ap);
IonSpew(IonSpew_Abort, "aborted @ %s:%d", script->filename, PCToLineNumber(script, pc));
IonSpew(IonSpew_Abort, "aborted @ %s:%d", script_->filename, PCToLineNumber(script_, pc));
#endif
return false;
}
@ -67,7 +67,7 @@ IonBuilder::spew(const char *message)
{
// Don't call PCToLineNumber in release builds.
#ifdef DEBUG
IonSpew(IonSpew_MIR, "%s @ %s:%d", message, script->filename, PCToLineNumber(script, pc));
IonSpew(IonSpew_MIR, "%s @ %s:%d", message, script_->filename, PCToLineNumber(script_, pc));
#endif
}
@ -146,7 +146,7 @@ IonBuilder::CFGState::LookupSwitch(jsbytecode *exitpc)
JSFunction *
IonBuilder::getSingleCallTarget(uint32 argc, jsbytecode *pc)
{
types::StackTypeSet *calleeTypes = oracle->getCallTarget(script, argc, pc);
types::StackTypeSet *calleeTypes = oracle->getCallTarget(script(), argc, pc);
if (!calleeTypes)
return NULL;
@ -161,7 +161,7 @@ uint32_t
IonBuilder::getPolyCallTargets(uint32 argc, jsbytecode *pc,
AutoObjectVector &targets, uint32_t maxTargets)
{
types::TypeSet *calleeTypes = oracle->getCallTarget(script, argc, pc);
types::TypeSet *calleeTypes = oracle->getCallTarget(script_, argc, pc);
if (!calleeTypes)
return 0;
@ -191,7 +191,7 @@ IonBuilder::canInlineTarget(JSFunction *target)
return false;
}
if (target->getParent() != &script->global()) {
if (target->getParent() != &script_->global()) {
IonSpew(IonSpew_Inlining, "Cannot inline due to scope mismatch");
return false;
}
@ -206,7 +206,7 @@ IonBuilder::canInlineTarget(JSFunction *target)
// Allow inlining of recursive calls, but only one level deep.
IonBuilder *builder = callerBuilder_;
while (builder) {
if (builder->script == inlineScript) {
if (builder->script() == inlineScript) {
IonSpew(IonSpew_Inlining, "Not inlining recursive call");
return false;
}
@ -216,7 +216,7 @@ IonBuilder::canInlineTarget(JSFunction *target)
bool canInline = oracle->canEnterInlinedFunction(target);
if (!canInline) {
IonSpew(IonSpew_Inlining, "Cannot inline due to oracle veto %d", script->lineno);
IonSpew(IonSpew_Inlining, "Cannot inline due to oracle veto %d", script_->lineno);
return false;
}
@ -265,10 +265,10 @@ IonBuilder::build()
return false;
IonSpew(IonSpew_Scripts, "Analyzing script %s:%d (%p) (usecount=%d) (maxloopcount=%d)",
script->filename, script->lineno, (void *)script, (int)script->getUseCount(),
(int)script->getMaxLoopCount());
script_->filename, script_->lineno, (void *)script_, (int)script_->getUseCount(),
(int)script_->getMaxLoopCount());
if (!graph().addScript(script))
if (!graph().addScript(script_))
return false;
if (!initParameters())
@ -294,7 +294,7 @@ IonBuilder::build()
// Emit the start instruction, so we can begin real instructions.
current->makeStart(MStart::New(MStart::StartType_Default));
if (instrumentedProfiling())
current->add(MFunctionBoundary::New(script, MFunctionBoundary::Enter));
current->add(MFunctionBoundary::New(script_, MFunctionBoundary::Enter));
// Parameters have been checked to correspond to the typeset, now we unbox
// what we can in an infallible manner.
@ -337,7 +337,7 @@ IonBuilder::build()
// Recompile to inline calls if this function is hot.
insertRecompileCheck();
if (script->argumentsHasVarBinding()) {
if (script_->argumentsHasVarBinding()) {
lazyArguments_ = MConstant::New(MagicValue(JS_OPTIMIZED_ARGUMENTS));
current->add(lazyArguments_);
}
@ -391,9 +391,9 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
MDefinition *thisDefn, MDefinitionVector &argv)
{
IonSpew(IonSpew_Scripts, "Inlining script %s:%d (%p)",
script->filename, script->lineno, (void *)script);
script_->filename, script_->lineno, (void *)script_);
if (!graph().addScript(script))
if (!graph().addScript(script_))
return false;
callerBuilder_ = callerBuilder;
@ -418,7 +418,7 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
// keep track of the inlining depth because all scripts inlined on the same
// level contiguously have only one Inline_Exit node.
if (instrumentedProfiling())
predecessor->add(MFunctionBoundary::New(script,
predecessor->add(MFunctionBoundary::New(script_,
MFunctionBoundary::Inline_Enter,
inliningDepth));
@ -442,7 +442,7 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
}
// The Oracle ensures that the inlined script does not use the scope chain.
JS_ASSERT(!script->analysis()->usesScopeChain());
JS_ASSERT(!script_->analysis()->usesScopeChain());
MInstruction *scope = MConstant::New(UndefinedValue());
current->add(scope);
current->initSlot(info().scopeChainSlot(), scope);
@ -533,12 +533,12 @@ IonBuilder::initParameters()
return true;
MParameter *param = MParameter::New(MParameter::THIS_SLOT,
oracle->thisTypeSet(script));
oracle->thisTypeSet(script_));
current->add(param);
current->initSlot(info().thisSlot(), param);
for (uint32 i = 0; i < info().nargs(); i++) {
param = MParameter::New(i, oracle->parameterTypeSet(script, i));
param = MParameter::New(i, oracle->parameterTypeSet(script_, i));
current->add(param);
current->initSlot(info().argSlot(i), param);
}
@ -553,14 +553,14 @@ IonBuilder::initScopeChain()
// If the script doesn't use the scopechain, then it's already initialized
// from earlier.
if (!script->analysis()->usesScopeChain())
if (!script_->analysis()->usesScopeChain())
return true;
// The scope chain is only tracked in scripts that have NAME opcodes which
// will try to access the scope. For other scripts, the scope instructions
// will be held live by resume points and code will still be generated for
// them, so just use a constant undefined value.
if (!script->compileAndGo)
if (!script_->compileAndGo)
return abort("non-CNG global scripts are not supported");
if (JSFunction *fun = info().fun()) {
@ -580,7 +580,7 @@ IonBuilder::initScopeChain()
return false;
}
} else {
scope = MConstant::New(ObjectValue(script->global()));
scope = MConstant::New(ObjectValue(script_->global()));
current->add(scope);
}
@ -743,7 +743,7 @@ IonBuilder::snoopControlFlow(JSOp op)
void
IonBuilder::markPhiBytecodeUses(jsbytecode *pc)
{
unsigned nuses = analyze::GetUseCount(script, pc - script->code);
unsigned nuses = analyze::GetUseCount(script_, pc - script_->code);
for (unsigned i = 0; i < nuses; i++) {
MDefinition *def = current->peek(-(i + 1));
if (def->isPassArg())
@ -947,7 +947,7 @@ IonBuilder::inspectOpcode(JSOp op)
}
case JSOP_BINDGNAME:
return pushConstant(ObjectValue(script->global()));
return pushConstant(ObjectValue(script_->global()));
case JSOP_SETGNAME:
{
@ -2290,7 +2290,7 @@ IonBuilder::lookupSwitch(JSOp op, jssrcnote *sn)
bool prevShared = false;
jsbytecode *prevpc = NULL;
for (unsigned int i = 0; i < ncases; i++) {
Value rval = script->getConst(GET_UINT32_INDEX(pc2));
Value rval = script_->getConst(GET_UINT32_INDEX(pc2));
pc2 += UINT32_INDEX_LEN;
jsbytecode *casepc = pc + GET_JUMP_OFFSET(pc2);
pc2 += JUMP_OFFSET_LEN;
@ -2570,7 +2570,7 @@ IonBuilder::processReturn(JSOp op)
}
if (instrumentedProfiling())
current->add(MFunctionBoundary::New(script, MFunctionBoundary::Exit));
current->add(MFunctionBoundary::New(script_, MFunctionBoundary::Exit));
MReturn *ret = MReturn::New(def);
current->end(ret);
@ -2614,7 +2614,7 @@ IonBuilder::jsop_bitnot()
MBitNot *ins = MBitNot::New(input);
current->add(ins);
ins->infer(oracle->unaryTypes(script, pc));
ins->infer(oracle->unaryTypes(script_, pc));
current->push(ins);
if (ins->isEffectful() && !resumeAfter(ins))
@ -2660,7 +2660,7 @@ IonBuilder::jsop_bitop(JSOp op)
}
current->add(ins);
ins->infer(oracle->binaryTypes(script, pc));
ins->infer(oracle->binaryTypes(script_, pc));
current->push(ins);
if (ins->isEffectful() && !resumeAfter(ins))
@ -2672,7 +2672,7 @@ IonBuilder::jsop_bitop(JSOp op)
bool
IonBuilder::jsop_binary(JSOp op, MDefinition *left, MDefinition *right)
{
TypeOracle::Binary b = oracle->binaryOp(script, pc);
TypeOracle::Binary b = oracle->binaryOp(script_, pc);
if (op == JSOP_ADD && b.rval == MIRType_String &&
(b.lhs == MIRType_String || b.lhs == MIRType_Int32) &&
@ -2711,7 +2711,7 @@ IonBuilder::jsop_binary(JSOp op, MDefinition *left, MDefinition *right)
return false;
}
TypeOracle::BinaryTypes types = oracle->binaryTypes(script, pc);
TypeOracle::BinaryTypes types = oracle->binaryTypes(script_, pc);
current->add(ins);
ins->infer(cx, types);
current->push(ins);
@ -2733,7 +2733,7 @@ IonBuilder::jsop_binary(JSOp op)
bool
IonBuilder::jsop_pos()
{
TypeOracle::Unary types = oracle->unaryOp(script, pc);
TypeOracle::Unary types = oracle->unaryOp(script_, pc);
if (IsNumberType(types.ival)) {
// Already int32 or double.
JS_ASSERT(IsNumberType(types.rval));
@ -2918,12 +2918,12 @@ IonBuilder::makeInliningDecision(AutoObjectVector &targets)
if (allFunctionsAreSmall)
checkUses = js_IonOptions.smallFunctionUsesBeforeInlining;
if (script->getUseCount() < checkUses) {
if (script_->getUseCount() < checkUses) {
IonSpew(IonSpew_Inlining, "Not inlining, caller is not hot");
return false;
}
if (!oracle->canInlineCall(script, pc)) {
if (!oracle->canInlineCall(script_, pc)) {
IonSpew(IonSpew_Inlining, "Cannot inline due to uninlineable call site");
return false;
}
@ -3423,7 +3423,7 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
// Create a template CallObject that we'll use to generate inline object
// creation.
RootedObject templateObj(cx, CallObject::createTemplateObject(cx, script));
RootedObject templateObj(cx, CallObject::createTemplateObject(cx, script_));
if (!templateObj)
return NULL;
@ -3449,7 +3449,7 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
current->add(MStoreFixedSlot::New(callObj, CallObject::enclosingScopeSlot(), scope));
// Initialize argument slots.
for (AliasedFormalIter i(script); i; i++) {
for (AliasedFormalIter i(script_); i; i++) {
unsigned slot = i.scopeSlot();
unsigned formal = i.frameIndex();
MDefinition *param = current->getSlot(info().argSlot(formal));
@ -3573,7 +3573,7 @@ IonBuilder::jsop_funcall(uint32 argc)
return makeCall(native, argc, false);
// Extract call target.
types::StackTypeSet *funTypes = oracle->getCallArg(script, argc, 0, pc);
types::StackTypeSet *funTypes = oracle->getCallArg(script_, argc, 0, pc);
RootedObject funobj(cx, (funTypes) ? funTypes->getSingleton() : NULL);
RootedFunction target(cx, (funobj && funobj->isFunction()) ? funobj->toFunction() : NULL);
@ -3615,7 +3615,7 @@ IonBuilder::jsop_funapply(uint32 argc)
// Disable compilation if the second argument to |apply| cannot be guaranteed
// to be either definitely |arguments| or definitely not |arguments|.
types::StackTypeSet *argObjTypes = oracle->getCallArg(script, argc, 2, pc);
types::StackTypeSet *argObjTypes = oracle->getCallArg(script_, argc, 2, pc);
LazyArgumentsType isArgObj = oracle->isArgumentObject(argObjTypes);
if (isArgObj == MaybeArguments)
return abort("fun.apply with MaybeArguments");
@ -3638,7 +3638,7 @@ IonBuilder::jsop_funapply(uint32 argc)
// argc+2: The native 'apply' function.
// Extract call target.
types::StackTypeSet *funTypes = oracle->getCallArg(script, argc, 0, pc);
types::StackTypeSet *funTypes = oracle->getCallArg(script_, argc, 0, pc);
RootedObject funobj(cx, (funTypes) ? funTypes->getSingleton() : NULL);
RootedFunction target(cx, (funobj && funobj->isFunction()) ? funobj->toFunction() : NULL);
@ -3672,7 +3672,7 @@ IonBuilder::jsop_funapply(uint32 argc)
return false;
types::StackTypeSet *barrier;
types::StackTypeSet *types = oracle->returnTypeSet(script, pc, &barrier);
types::StackTypeSet *types = oracle->returnTypeSet(script_, pc, &barrier);
return pushTypeBarrier(apply, types, barrier);
}
@ -3718,7 +3718,7 @@ IonBuilder::jsop_call(uint32 argc, bool constructing)
AutoObjectVector targets(cx);
uint32_t numTargets = getPolyCallTargets(argc, pc, targets, 4);
types::StackTypeSet *barrier;
types::StackTypeSet *types = oracle->returnTypeSet(script, pc, &barrier);
types::StackTypeSet *types = oracle->returnTypeSet(script_, pc, &barrier);
// Attempt to inline native and scripted functions.
if (inliningEnabled()) {
@ -3747,7 +3747,7 @@ IonBuilder::jsop_call(uint32 argc, bool constructing)
// or will only be used to test for existence.
if (target->maybeNative() == regexp_exec && !CallResultEscapes(pc)) {
JSFunction *newTarget = NULL;
if (!GetBuiltinRegExpTest(cx, script, &newTarget))
if (!GetBuiltinRegExpTest(cx, script_, &newTarget))
return false;
if (newTarget)
target = newTarget;
@ -3848,7 +3848,7 @@ bool
IonBuilder::makeCall(HandleFunction target, uint32 argc, bool constructing)
{
types::StackTypeSet *barrier;
types::StackTypeSet *types = oracle->returnTypeSet(script, pc, &barrier);
types::StackTypeSet *types = oracle->returnTypeSet(script_, pc, &barrier);
return makeCallBarrier(target, argc, constructing, types, barrier);
}
@ -3857,7 +3857,7 @@ IonBuilder::jsop_incslot(JSOp op, uint32 slot)
{
int32 amt = (js_CodeSpec[op].format & JOF_INC) ? 1 : -1;
bool post = !!(js_CodeSpec[op].format & JOF_POST);
TypeOracle::BinaryTypes types = oracle->incslot(script, pc);
TypeOracle::BinaryTypes types = oracle->incslot(script_, pc);
// Grab the value at the local slot, and convert it to a number. Currently,
// we use ToInt32 or ToNumber which are fallible but idempotent. This whole
@ -3918,7 +3918,7 @@ IonBuilder::jsop_compare(JSOp op)
current->add(ins);
current->push(ins);
ins->infer(cx, oracle->binaryTypes(script, pc));
ins->infer(cx, oracle->binaryTypes(script_, pc));
if (ins->isEffectful() && !resumeAfter(ins))
return false;
@ -3932,6 +3932,7 @@ IonBuilder::getNewArrayTemplateObject(uint32 count)
if (!templateObject)
return NULL;
RootedScript script(cx, script_);
if (types::UseNewTypeForInitializer(cx, script, pc, JSProto_Array)) {
if (!JSObject::setSingletonType(cx, templateObject))
return NULL;
@ -3948,7 +3949,7 @@ IonBuilder::getNewArrayTemplateObject(uint32 count)
bool
IonBuilder::jsop_newarray(uint32 count)
{
JS_ASSERT(script->compileAndGo);
JS_ASSERT(script_->compileAndGo);
JSObject *templateObject = getNewArrayTemplateObject(count);
if (!templateObject)
@ -3966,7 +3967,7 @@ bool
IonBuilder::jsop_newobject(HandleObject baseObj)
{
// Don't bake in the TypeObject for non-CNG scripts.
JS_ASSERT(script->compileAndGo);
JS_ASSERT(script_->compileAndGo);
RootedObject templateObject(cx);
@ -3980,6 +3981,7 @@ IonBuilder::jsop_newobject(HandleObject baseObj)
if (!templateObject)
return false;
RootedScript script(cx, script_);
if (types::UseNewTypeForInitializer(cx, script, pc, JSProto_Object)) {
if (!JSObject::setSingletonType(cx, templateObject))
return false;
@ -4001,8 +4003,8 @@ IonBuilder::jsop_newobject(HandleObject baseObj)
bool
IonBuilder::jsop_initelem()
{
if (oracle->propertyWriteCanSpecialize(script, pc)) {
if (oracle->elementWriteIsDenseArray(script, pc))
if (oracle->propertyWriteCanSpecialize(script_, pc)) {
if (oracle->elementWriteIsDenseArray(script_, pc))
return jsop_initelem_dense();
}
@ -4055,7 +4057,7 @@ IonBuilder::jsop_initprop(HandlePropertyName name)
RootedObject templateObject(cx, obj->toNewObject()->templateObject());
if (!oracle->propertyWriteCanSpecialize(script, pc)) {
if (!oracle->propertyWriteCanSpecialize(script_, pc)) {
// This should only happen for a few names like __proto__.
return abort("INITPROP Monitored initprop");
}
@ -4079,7 +4081,7 @@ IonBuilder::jsop_initprop(HandlePropertyName name)
}
bool needsBarrier = true;
TypeOracle::BinaryTypes b = oracle->binaryTypes(script, pc);
TypeOracle::BinaryTypes b = oracle->binaryTypes(script_, pc);
if (b.lhsTypes &&
((jsid)id == types::MakeTypeId(cx, id)) &&
!b.lhsTypes->propertyNeedsBarrier(cx, id))
@ -4373,7 +4375,7 @@ IonBuilder::insertRecompileCheck()
return;
// Don't recompile if we are already inlining.
if (script->getUseCount() >= js_IonOptions.usesBeforeInlining)
if (script_->getUseCount() >= js_IonOptions.usesBeforeInlining)
return;
// Don't recompile if the oracle cannot provide inlining information
@ -4381,7 +4383,7 @@ IonBuilder::insertRecompileCheck()
if (!oracle->canInlineCalls())
return;
uint32_t minUses = UsesBeforeIonRecompile(script, pc);
uint32_t minUses = UsesBeforeIonRecompile(script_, pc);
MRecompileCheck *check = MRecompileCheck::New(minUses);
current->add(check);
}
@ -4632,7 +4634,7 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
if (name == cx->names().Infinity)
return pushConstant(cx->runtime->positiveInfinityValue);
RootedObject globalObj(cx, &script->global());
RootedObject globalObj(cx, &script_->global());
JS_ASSERT(globalObj->isNative());
RootedId id(cx, NameToId(name));
@ -4643,7 +4645,7 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
return jsop_getname(name);
types::HeapTypeSet *propertyTypes = oracle->globalPropertyTypeSet(script, pc, id);
types::HeapTypeSet *propertyTypes = oracle->globalPropertyTypeSet(script_, pc, id);
if (propertyTypes && propertyTypes->isOwnProperty(cx, globalObj->getType(cx), true)) {
// The property has been reconfigured as non-configurable, non-enumerable
// or non-writable.
@ -4653,8 +4655,8 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
// If the property is permanent, a shape guard isn't necessary.
JSValueType knownType = JSVAL_TYPE_UNKNOWN;
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
types::StackTypeSet *types = oracle->propertyRead(script, pc);
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
types::StackTypeSet *types = oracle->propertyRead(script_, pc);
if (types) {
JSObject *singleton = types->getSingleton();
@ -4703,13 +4705,13 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
bool
IonBuilder::jsop_setgname(HandlePropertyName name)
{
RootedObject globalObj(cx, &script->global());
RootedObject globalObj(cx, &script_->global());
RootedId id(cx, NameToId(name));
JS_ASSERT(globalObj->isNative());
bool canSpecialize;
types::HeapTypeSet *propertyTypes = oracle->globalPropertyWrite(script, pc, id, &canSpecialize);
types::HeapTypeSet *propertyTypes = oracle->globalPropertyWrite(script_, pc, id, &canSpecialize);
// This should only happen for a few names like __proto__.
if (!canSpecialize || globalObj->watched())
@ -4776,7 +4778,7 @@ IonBuilder::jsop_getname(HandlePropertyName name)
{
MDefinition *object;
if (js_CodeSpec[*pc].format & JOF_GNAME) {
MInstruction *global = MConstant::New(ObjectValue(script->global()));
MInstruction *global = MConstant::New(ObjectValue(script_->global()));
current->add(global);
object = global;
} else {
@ -4796,8 +4798,8 @@ IonBuilder::jsop_getname(HandlePropertyName name)
if (!resumeAfter(ins))
return false;
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
types::StackTypeSet *types = oracle->propertyRead(script, pc);
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
types::StackTypeSet *types = oracle->propertyRead(script_, pc);
monitorResult(ins, types);
return pushTypeBarrier(ins, types, barrier);
@ -4806,10 +4808,10 @@ IonBuilder::jsop_getname(HandlePropertyName name)
bool
IonBuilder::jsop_bindname(PropertyName *name)
{
JS_ASSERT(script->analysis()->usesScopeChain());
JS_ASSERT(script_->analysis()->usesScopeChain());
MDefinition *scopeChain = current->scopeChain();
MBindNameCache *ins = MBindNameCache::New(scopeChain, name, script, pc);
MBindNameCache *ins = MBindNameCache::New(scopeChain, name, script_, pc);
current->add(ins);
current->push(ins);
@ -4820,17 +4822,17 @@ IonBuilder::jsop_bindname(PropertyName *name)
bool
IonBuilder::jsop_getelem()
{
if (oracle->elementReadIsDenseArray(script, pc))
if (oracle->elementReadIsDenseArray(script_, pc))
return jsop_getelem_dense();
int arrayType = TypedArray::TYPE_MAX;
if (oracle->elementReadIsTypedArray(script, pc, &arrayType))
if (oracle->elementReadIsTypedArray(script_, pc, &arrayType))
return jsop_getelem_typed(arrayType);
if (oracle->elementReadIsString(script, pc))
if (oracle->elementReadIsString(script_, pc))
return jsop_getelem_string();
LazyArgumentsType isArguments = oracle->elementReadMagicArguments(script, pc);
LazyArgumentsType isArguments = oracle->elementReadMagicArguments(script_, pc);
if (isArguments == MaybeArguments)
return abort("Type is not definitely lazy arguments.");
if (isArguments == DefinitelyArguments)
@ -4848,7 +4850,7 @@ IonBuilder::jsop_getelem()
bool mustMonitorResult = false;
bool cacheable = false;
oracle->elementReadGeneric(script, pc, &cacheable, &mustMonitorResult);
oracle->elementReadGeneric(script_, pc, &cacheable, &mustMonitorResult);
if (cacheable)
ins = MGetElementCache::New(lhs, rhs, mustMonitorResult);
@ -4861,8 +4863,8 @@ IonBuilder::jsop_getelem()
if (!resumeAfter(ins))
return false;
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
types::StackTypeSet *types = oracle->propertyRead(script, pc);
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
types::StackTypeSet *types = oracle->propertyRead(script_, pc);
if (mustMonitorResult)
monitorResult(ins, types);
@ -4875,9 +4877,9 @@ IonBuilder::jsop_getelem_dense()
if (oracle->arrayPrototypeHasIndexedProperty())
return abort("GETELEM Array proto has indexed properties");
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
types::StackTypeSet *types = oracle->propertyRead(script, pc);
bool needsHoleCheck = !oracle->elementReadIsPacked(script, pc);
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
types::StackTypeSet *types = oracle->propertyRead(script_, pc);
bool needsHoleCheck = !oracle->elementReadIsPacked(script_, pc);
bool maybeUndefined = types->hasType(types::Type::UndefinedType());
MDefinition *id = current->pop();
@ -4964,8 +4966,8 @@ GetTypedArrayElements(MDefinition *obj)
bool
IonBuilder::jsop_getelem_typed(int arrayType)
{
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
types::StackTypeSet *types = oracle->propertyRead(script, pc);
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
types::StackTypeSet *types = oracle->propertyRead(script_, pc);
MDefinition *id = current->pop();
MDefinition *obj = current->pop();
@ -5074,16 +5076,16 @@ IonBuilder::jsop_getelem_string()
bool
IonBuilder::jsop_setelem()
{
if (oracle->propertyWriteCanSpecialize(script, pc)) {
if (oracle->elementWriteIsDenseArray(script, pc))
if (oracle->propertyWriteCanSpecialize(script_, pc)) {
if (oracle->elementWriteIsDenseArray(script_, pc))
return jsop_setelem_dense();
int arrayType = TypedArray::TYPE_MAX;
if (oracle->elementWriteIsTypedArray(script, pc, &arrayType))
if (oracle->elementWriteIsTypedArray(script_, pc, &arrayType))
return jsop_setelem_typed(arrayType);
}
LazyArgumentsType isArguments = oracle->elementWriteMagicArguments(script, pc);
LazyArgumentsType isArguments = oracle->elementWriteMagicArguments(script_, pc);
if (isArguments == MaybeArguments)
return abort("Type is not definitely lazy arguments.");
if (isArguments == DefinitelyArguments)
@ -5106,8 +5108,8 @@ IonBuilder::jsop_setelem_dense()
if (oracle->arrayPrototypeHasIndexedProperty())
return abort("SETELEM Array proto has indexed properties");
MIRType elementType = oracle->elementWrite(script, pc);
bool packed = oracle->elementWriteIsPacked(script, pc);
MIRType elementType = oracle->elementWrite(script_, pc);
bool packed = oracle->elementWriteIsPacked(script_, pc);
MDefinition *value = current->pop();
MDefinition *id = current->pop();
@ -5126,7 +5128,7 @@ IonBuilder::jsop_setelem_dense()
// indexes in the past. Otherwise, use MStoreElement so that we can hoist
// the initialized length and bounds check.
MStoreElementCommon *store;
if (oracle->setElementHasWrittenHoles(script, pc)) {
if (oracle->setElementHasWrittenHoles(script_, pc)) {
MStoreElementHole *ins = MStoreElementHole::New(obj, elements, id, value);
store = ins;
@ -5152,7 +5154,7 @@ IonBuilder::jsop_setelem_dense()
}
// Determine whether a write barrier is required.
if (oracle->elementWriteNeedsBarrier(script, pc))
if (oracle->elementWriteNeedsBarrier(script_, pc))
store->setNeedsBarrier();
if (elementType != MIRType_None && packed)
@ -5212,7 +5214,7 @@ IonBuilder::jsop_length()
bool
IonBuilder::jsop_length_fastPath()
{
TypeOracle::UnaryTypes sig = oracle->unaryTypes(script, pc);
TypeOracle::UnaryTypes sig = oracle->unaryTypes(script_, pc);
if (!sig.inTypes || !sig.outTypes)
return false;
@ -5282,8 +5284,8 @@ IonBuilder::jsop_arguments_length()
bool
IonBuilder::jsop_arguments_getelem()
{
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
types::StackTypeSet *types = oracle->propertyRead(script, pc);
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
types::StackTypeSet *types = oracle->propertyRead(script_, pc);
MDefinition *idx = current->pop();
@ -5389,7 +5391,7 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
types::HeapTypeSet *propSet = typeObj->getProperty(cx, typeId, false);
if (!propSet)
return false;
if (propSet->isOwnProperty(cx, typeObj, false))
if (propSet->ownProperty(false))
return true;
// Check the DOM status of the instance type
@ -5452,21 +5454,32 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
else if (foundProto != proto)
return true;
// Check here to make sure that everyone has Type Objects which known
// Check here to make sure that everyone has Type Objects with known
// properties between them and the proto we found the accessor on. We
// need those to add freezes safely. NOTE: We do not do this above, as
// we may be able to freeze all the types up to where we found the
// property, even if there are unknown types higher in the prototype
// chain.
while (curObj != foundProto) {
if (curObj->getType(cx)->unknownProperties())
types::TypeObject *typeObj = curObj->getType(cx);
if (typeObj->unknownProperties())
return true;
// If anyone on the chain is watched, TI thinks they have an own
// property, which means if they were to actually overwrite the
// property accessors, we would never know, since we are freezing on
// setting that flag.
if (curObj->watched())
// Check here to make sure that nobody on the prototype chain is
// marked as having the property as an "own property". This can
// happen in cases of |delete| having been used, or cases with
// watched objects. If TI ever decides to be more accurate about
// |delete| handling, this should go back to curObj->watched().
// Even though we are not directly accessing the properties on the whole
// prototype chain, we need to fault in the sets anyway, as we need
// to freeze on them.
jsid typeId = types::MakeTypeId(cx, id);
types::HeapTypeSet *propSet = typeObj->getProperty(cx, typeId, false);
if (!propSet)
return false;
if (propSet->ownProperty(false))
return true;
curObj = curObj->getProto();
@ -5518,6 +5531,8 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
jsid typeId = types::MakeTypeId(cx, id);
while (true) {
types::HeapTypeSet *propSet = curType->getProperty(cx, typeId, false);
// This assert is now assured, since we have faulted them in
// above.
JS_ASSERT(propSet);
// Asking, freeze by asking.
DebugOnly<bool> isOwn = propSet->isOwnProperty(cx, curType, false);
@ -5734,7 +5749,7 @@ IonBuilder::invalidatedIdempotentCache()
{
IonBuilder *builder = this;
do {
if (builder->script->invalidatedIdempotentCache)
if (builder->script()->invalidatedIdempotentCache)
return true;
builder = builder->callerBuilder_;
} while (builder);
@ -5748,8 +5763,8 @@ IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType)
JS_ASSERT(shape->hasDefaultGetter());
JS_ASSERT(shape->hasSlot());
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
types::StackTypeSet *types = oracle->propertyRead(script, pc);
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
types::StackTypeSet *types = oracle->propertyRead(script_, pc);
if (shape->slot() < shape->numFixedSlots()) {
MLoadFixedSlot *load = MLoadFixedSlot::New(obj, shape->slot());
@ -5801,7 +5816,7 @@ IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool n
bool
IonBuilder::jsop_getprop(HandlePropertyName name)
{
LazyArgumentsType isArguments = oracle->propertyReadMagicArguments(script, pc);
LazyArgumentsType isArguments = oracle->propertyReadMagicArguments(script_, pc);
if (isArguments == MaybeArguments)
return abort("Type is not definitely lazy arguments.");
if (isArguments == DefinitelyArguments) {
@ -5813,18 +5828,18 @@ IonBuilder::jsop_getprop(HandlePropertyName name)
MDefinition *obj = current->pop();
MInstruction *ins;
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
types::StackTypeSet *types = oracle->propertyRead(script, pc);
types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
types::StackTypeSet *types = oracle->propertyRead(script_, pc);
TypeOracle::Unary unary = oracle->unaryOp(script, pc);
TypeOracle::UnaryTypes unaryTypes = oracle->unaryTypes(script, pc);
TypeOracle::Unary unary = oracle->unaryOp(script_, pc);
TypeOracle::UnaryTypes unaryTypes = oracle->unaryTypes(script_, pc);
RootedId id(cx, NameToId(name));
JSObject *singleton = types ? types->getSingleton() : NULL;
if (singleton && !barrier) {
bool isKnownConstant, testObject;
RootedObject global(cx, &script->global());
RootedObject global(cx, &script_->global());
if (!TestSingletonPropertyTypes(cx, unaryTypes.inTypes,
global, id,
&isKnownConstant, &testObject))
@ -5905,7 +5920,7 @@ IonBuilder::jsop_getprop(HandlePropertyName name)
rvalType = unary.rval;
Shape *objShape;
if ((objShape = mjit::GetPICSingleShape(cx, script, pc, info().constructing())) &&
if ((objShape = mjit::GetPICSingleShape(cx, script_, pc, info().constructing())) &&
!objShape->inDictionary())
{
// The JM IC was monomorphic, so we inline the property access as
@ -5935,7 +5950,7 @@ IonBuilder::jsop_getprop(HandlePropertyName name)
if ((cx->methodJitEnabled || js_IonOptions.eagerCompilation) &&
!invalidatedIdempotentCache())
{
if (oracle->propertyReadIdempotent(script, pc, id))
if (oracle->propertyReadIdempotent(script_, pc, id))
load->setIdempotent();
}
@ -5965,9 +5980,9 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
MDefinition *value = current->pop();
MDefinition *obj = current->pop();
bool monitored = !oracle->propertyWriteCanSpecialize(script, pc);
bool monitored = !oracle->propertyWriteCanSpecialize(script_, pc);
TypeOracle::BinaryTypes binaryTypes = oracle->binaryTypes(script, pc);
TypeOracle::BinaryTypes binaryTypes = oracle->binaryTypes(script_, pc);
if (!monitored) {
if (types::HeapTypeSet *propTypes = GetDefiniteSlot(cx, binaryTypes.lhsTypes, name)) {
@ -6021,14 +6036,14 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
return resumeAfter(call);
}
oracle->binaryOp(script, pc);
oracle->binaryOp(script_, pc);
MSetPropertyInstruction *ins;
if (monitored) {
ins = MCallSetProperty::New(obj, value, name, script->strictModeCode);
ins = MCallSetProperty::New(obj, value, name, script_->strictModeCode);
} else {
Shape *objShape;
if ((objShape = mjit::GetPICSingleShape(cx, script, pc, info().constructing())) &&
if ((objShape = mjit::GetPICSingleShape(cx, script_, pc, info().constructing())) &&
!objShape->inDictionary())
{
// The JM IC was monomorphic, so we inline the property access as
@ -6044,14 +6059,14 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
spew("Inlining monomorphic SETPROP");
jsid typeId = types::MakeTypeId(cx, id);
bool needsBarrier = oracle->propertyWriteNeedsBarrier(script, pc, typeId);
bool needsBarrier = oracle->propertyWriteNeedsBarrier(script_, pc, typeId);
return storeSlot(obj, shape, value, needsBarrier);
}
spew("SETPROP not monomorphic");
ins = MSetPropertyCache::New(obj, value, name, script->strictModeCode);
ins = MSetPropertyCache::New(obj, value, name, script_->strictModeCode);
if (!binaryTypes.lhsTypes || binaryTypes.lhsTypes->propertyNeedsBarrier(cx, id))
ins->setNeedsBarrier();
@ -6079,7 +6094,7 @@ IonBuilder::jsop_delprop(HandlePropertyName name)
bool
IonBuilder::jsop_regexp(RegExpObject *reobj)
{
JSObject *prototype = script->global().getOrCreateRegExpPrototype(cx);
JSObject *prototype = script_->global().getOrCreateRegExpPrototype(cx);
if (!prototype)
return false;
@ -6103,7 +6118,7 @@ IonBuilder::jsop_object(JSObject *obj)
bool
IonBuilder::jsop_lambda(JSFunction *fun)
{
JS_ASSERT(script->analysis()->usesScopeChain());
JS_ASSERT(script_->analysis()->usesScopeChain());
MLambda *ins = MLambda::New(current->scopeChain(), fun);
current->add(ins);
current->push(ins);
@ -6114,7 +6129,7 @@ IonBuilder::jsop_lambda(JSFunction *fun)
bool
IonBuilder::jsop_deflocalfun(uint32 local, JSFunction *fun)
{
JS_ASSERT(script->analysis()->usesScopeChain());
JS_ASSERT(script_->analysis()->usesScopeChain());
MLambda *ins = MLambda::New(current->scopeChain(), fun);
current->add(ins);
@ -6131,7 +6146,7 @@ IonBuilder::jsop_defvar(uint32 index)
{
JS_ASSERT(JSOp(*pc) == JSOP_DEFVAR || JSOp(*pc) == JSOP_DEFCONST);
PropertyName *name = script->getName(index);
PropertyName *name = script_->getName(index);
// Bake in attrs.
unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
@ -6139,7 +6154,7 @@ IonBuilder::jsop_defvar(uint32 index)
attrs |= JSPROP_READONLY;
// Pass the ScopeChain.
JS_ASSERT(script->analysis()->usesScopeChain());
JS_ASSERT(script_->analysis()->usesScopeChain());
// Bake the name pointer into the MDefVar.
MDefVar *defvar = MDefVar::New(name, attrs, current->scopeChain());
@ -6154,12 +6169,12 @@ IonBuilder::jsop_this()
if (!info().fun())
return abort("JSOP_THIS outside of a JSFunction.");
if (script->strictModeCode) {
if (script_->strictModeCode) {
current->pushSlot(info().thisSlot());
return true;
}
types::StackTypeSet *types = oracle->thisTypeSet(script);
types::StackTypeSet *types = oracle->thisTypeSet(script_);
if (types && types->getKnownTypeTag() == JSVAL_TYPE_OBJECT) {
// This is safe, because if the entry type of |this| is an object, it
// will necessarily be an object throughout the entire function. OSR
@ -6174,7 +6189,7 @@ IonBuilder::jsop_this()
bool
IonBuilder::jsop_typeof()
{
TypeOracle::Unary unary = oracle->unaryOp(script, pc);
TypeOracle::Unary unary = oracle->unaryOp(script_, pc);
MDefinition *input = current->pop();
MTypeOf *ins = MTypeOf::New(input, unary.ival);
@ -6191,7 +6206,7 @@ bool
IonBuilder::jsop_toid()
{
// No-op if the index is an integer.
TypeOracle::Unary unary = oracle->unaryOp(script, pc);
TypeOracle::Unary unary = oracle->unaryOp(script_, pc);
if (unary.ival == MIRType_Int32)
return true;
@ -6272,11 +6287,11 @@ bool
IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
{
types::StackTypeSet *barrier;
types::StackTypeSet *actual = oracle->aliasedVarBarrier(script, pc, &barrier);
types::StackTypeSet *actual = oracle->aliasedVarBarrier(script_, pc, &barrier);
MDefinition *obj = walkScopeChain(sc.hops);
RootedShape shape(cx, ScopeCoordinateToStaticScope(script, pc).scopeShape());
RootedShape shape(cx, ScopeCoordinateToStaticScope(script_, pc).scopeShape());
MInstruction *load;
if (shape->numFixedSlots() <= sc.slot) {
@ -6310,7 +6325,7 @@ IonBuilder::jsop_setaliasedvar(ScopeCoordinate sc)
MDefinition *rval = current->peek(-1);
MDefinition *obj = walkScopeChain(sc.hops);
RootedShape shape(cx, ScopeCoordinateToStaticScope(script, pc).scopeShape());
RootedShape shape(cx, ScopeCoordinateToStaticScope(script_, pc).scopeShape());
MInstruction *store;
if (shape->numFixedSlots() <= sc.slot) {

View File

@ -415,10 +415,10 @@ class IonBuilder : public MIRGenerator
MBasicBlock *bottom,
Vector<MDefinition *, 8, IonAllocPolicy> &retvalDefns);
public:
// A builder is inextricably tied to a particular script.
JSScript * const script;
HeapPtrScript script_;
public:
// Compilation index for this attempt.
types::RecompileInfo const recompileInfo;
@ -427,6 +427,8 @@ class IonBuilder : public MIRGenerator
void clearForBackEnd();
JSScript *script() const { return script_; }
private:
JSContext *cx;

View File

@ -314,7 +314,7 @@ js::ion::GetPropertyCache(JSContext *cx, size_t cacheIndex, HandleObject obj, Mu
RootedScript script(cx);
jsbytecode *pc;
cache.getScriptedLocation(script.address(), &pc);
cache.getScriptedLocation(&script, &pc);
// Override the return value if we are invalidated (bug 728188).
AutoDetectInvalidation adi(cx, vp.address(), ion);
@ -831,7 +831,7 @@ js::ion::GetElementCache(JSContext *cx, size_t cacheIndex, HandleObject obj, Han
}
}
JSScript *script;
RootedScript script(cx);
jsbytecode *pc;
cache.getScriptedLocation(&script, &pc);
@ -1155,7 +1155,7 @@ js::ion::GetNameCache(JSContext *cx, size_t cacheIndex, HandleObject scopeChain,
IonCacheName &cache = ion->getCache(cacheIndex).toName();
RootedPropertyName name(cx, cache.name());
JSScript *script;
RootedScript script(cx);
jsbytecode *pc;
cache.getScriptedLocation(&script, &pc);

View File

@ -233,8 +233,8 @@ class IonCache
this->pc = pc;
}
void getScriptedLocation(JSScript **pscript, jsbytecode **ppc) {
*pscript = script;
void getScriptedLocation(MutableHandleScript pscript, jsbytecode **ppc) {
pscript.set(script);
*ppc = pc;
}
};

View File

@ -657,7 +657,7 @@ ion::AutoTempAllocatorRooter::trace(JSTracer *trc)
}
void
ion::GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
ion::GetPcScript(JSContext *cx, MutableHandleScript scriptRes, jsbytecode **pcRes)
{
JS_ASSERT(cx->fp()->beginsIonActivation());
IonSpew(IonSpew_Snapshots, "Recover PC & Script from the last frame.");
@ -668,7 +668,7 @@ ion::GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
InlineFrameIterator ifi(&it);
// Set the result.
*scriptRes = ifi.script();
scriptRes.set(ifi.script());
if (pcRes)
*pcRes = ifi.pc();
}

View File

@ -262,7 +262,7 @@ GetTopIonJSScript(JSContext *cx,
void **returnAddrOut = NULL);
void
GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes);
GetPcScript(JSContext *cx, MutableHandleScript scriptRes, jsbytecode **pcRes);
// Given a slot index, returns the offset, in bytes, of that slot from an
// IonJSFrameLayout. Slot distances are uniform across architectures, however,

View File

@ -99,7 +99,7 @@ types::StackTypeSet *
IonBuilder::getInlineReturnTypeSet()
{
types::StackTypeSet *barrier;
types::StackTypeSet *returnTypes = oracle->returnTypeSet(script, pc, &barrier);
types::StackTypeSet *returnTypes = oracle->returnTypeSet(script_, pc, &barrier);
JS_ASSERT(returnTypes);
return returnTypes;
@ -115,7 +115,7 @@ IonBuilder::getInlineReturnType()
types::StackTypeSet *
IonBuilder::getInlineArgTypeSet(uint32 argc, uint32 arg)
{
types::StackTypeSet *argTypes = oracle->getCallArg(script, argc, arg, pc);
types::StackTypeSet *argTypes = oracle->getCallArg(script_, argc, arg, pc);
JS_ASSERT(argTypes);
return argTypes;
}
@ -245,6 +245,7 @@ IonBuilder::inlineArrayPopShift(MArrayPopShift::Mode mode, uint32 argc, bool con
types::StackTypeSet *thisTypes = getInlineArgTypeSet(argc, 0);
if (thisTypes->hasObjectFlags(cx, unhandledFlags))
return InliningStatus_NotInlined;
RootedScript script(cx, script_);
if (types::ArrayPrototypeHasIndexedProperty(cx, script))
return InliningStatus_NotInlined;
@ -282,6 +283,7 @@ IonBuilder::inlineArrayPush(uint32 argc, bool constructing)
types::StackTypeSet *thisTypes = getInlineArgTypeSet(argc, 0);
if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY))
return InliningStatus_NotInlined;
RootedScript script(cx, script_);
if (types::ArrayPrototypeHasIndexedProperty(cx, script))
return InliningStatus_NotInlined;

View File

@ -21,7 +21,7 @@ bool
TypeInferenceOracle::init(JSContext *cx, JSScript *script)
{
this->cx = cx;
this->script = script;
this->script_.init(script);
return script->ensureRanInference(cx);
}
@ -66,7 +66,7 @@ TypeInferenceOracle::getMIRType(HeapTypeSet *types)
TypeOracle::UnaryTypes
TypeInferenceOracle::unaryTypes(JSScript *script, jsbytecode *pc)
{
JS_ASSERT(script == this->script);
JS_ASSERT(script == this->script_);
UnaryTypes res;
res.inTypes = script->analysis()->poppedTypes(pc, 0);
@ -77,7 +77,7 @@ TypeInferenceOracle::unaryTypes(JSScript *script, jsbytecode *pc)
TypeOracle::BinaryTypes
TypeInferenceOracle::binaryTypes(JSScript *script, jsbytecode *pc)
{
JS_ASSERT(script == this->script);
JS_ASSERT(script == this->script_);
JSOp op = (JSOp)*pc;
@ -121,7 +121,7 @@ TypeInferenceOracle::incslot(JSScript *script, jsbytecode *pc)
TypeOracle::Unary
TypeInferenceOracle::unaryOp(JSScript *script, jsbytecode *pc)
{
JS_ASSERT(script == this->script);
JS_ASSERT(script == this->script_);
Unary res;
res.ival = getMIRType(script->analysis()->poppedTypes(pc, 0));
@ -132,7 +132,7 @@ TypeInferenceOracle::unaryOp(JSScript *script, jsbytecode *pc)
TypeOracle::Binary
TypeInferenceOracle::binaryOp(JSScript *script, jsbytecode *pc)
{
JS_ASSERT(script == this->script);
JS_ASSERT(script == this->script_);
JSOp op = (JSOp)*pc;
@ -152,7 +152,7 @@ TypeInferenceOracle::binaryOp(JSScript *script, jsbytecode *pc)
StackTypeSet *
TypeInferenceOracle::thisTypeSet(JSScript *script)
{
JS_ASSERT(script == this->script);
JS_ASSERT(script == this->script_);
return TypeScript::ThisTypes(script);
}
@ -160,18 +160,18 @@ bool
TypeInferenceOracle::getOsrTypes(jsbytecode *osrPc, Vector<MIRType> &slotTypes)
{
JS_ASSERT(JSOp(*osrPc) == JSOP_LOOPENTRY);
JS_ASSERT(script->code < osrPc);
JS_ASSERT(osrPc < script->code + script->length);
JS_ASSERT(script_->code < osrPc);
JS_ASSERT(osrPc < script_->code + script_->length);
Vector<types::StackTypeSet *> slotTypeSets(cx);
if (!slotTypeSets.resize(TotalSlots(script)))
if (!slotTypeSets.resize(TotalSlots(script_)))
return false;
for (uint32_t slot = ThisSlot(); slot < TotalSlots(script); slot++)
slotTypeSets[slot] = TypeScript::SlotTypes(script, slot);
for (uint32_t slot = ThisSlot(); slot < TotalSlots(script_); slot++)
slotTypeSets[slot] = TypeScript::SlotTypes(script_, slot);
jsbytecode *pc = script->code;
ScriptAnalysis *analysis = script->analysis();
jsbytecode *pc = script_->code;
ScriptAnalysis *analysis = script_->analysis();
// To determine the slot types at the OSR pc, we have to do a forward walk
// over the bytecode to reconstruct the types.
@ -182,7 +182,7 @@ TypeInferenceOracle::getOsrTypes(jsbytecode *osrPc, Vector<MIRType> &slotTypes)
// Update variable types for all new values at this bytecode.
if (const SlotValue *newv = analysis->newValues(pc)) {
while (newv->slot) {
if (newv->slot < TotalSlots(script))
if (newv->slot < TotalSlots(script_))
slotTypeSets[newv->slot] = analysis->getValueTypes(newv->value);
newv++;
}
@ -190,7 +190,7 @@ TypeInferenceOracle::getOsrTypes(jsbytecode *osrPc, Vector<MIRType> &slotTypes)
}
if (BytecodeUpdatesSlot(JSOp(*pc))) {
uint32_t slot = GetBytecodeSlot(script, pc);
uint32_t slot = GetBytecodeSlot(script_, pc);
if (analysis->trackSlot(slot))
slotTypeSets[slot] = analysis->pushedTypes(pc, 0);
}
@ -213,15 +213,15 @@ TypeInferenceOracle::getOsrTypes(jsbytecode *osrPc, Vector<MIRType> &slotTypes)
uint32_t stackDepth = analysis->getCode(osrPc).stackDepth;
#endif
if (script->function()) {
JS_ASSERT(slotTypes.length() == TotalSlots(script) + stackDepth);
if (script_->function()) {
JS_ASSERT(slotTypes.length() == TotalSlots(script_) + stackDepth);
for (size_t i = ThisSlot(); i < TotalSlots(script); i++)
for (size_t i = ThisSlot(); i < TotalSlots(script_); i++)
slotTypes[i] = getMIRType(slotTypeSets[i]);
} else {
JS_ASSERT(slotTypes.length() == TotalSlots(script) + stackDepth - 1);
JS_ASSERT(slotTypes.length() == TotalSlots(script_) + stackDepth - 1);
for (size_t i = ArgSlot(0); i < TotalSlots(script); i++)
for (size_t i = ArgSlot(0); i < TotalSlots(script_); i++)
slotTypes[i - 1] = getMIRType(slotTypeSets[i]);
}
@ -231,7 +231,7 @@ TypeInferenceOracle::getOsrTypes(jsbytecode *osrPc, Vector<MIRType> &slotTypes)
StackTypeSet *
TypeInferenceOracle::parameterTypeSet(JSScript *script, size_t index)
{
JS_ASSERT(script == this->script);
JS_ASSERT(script == this->script_);
return TypeScript::ArgTypes(script, index);
}
@ -468,13 +468,14 @@ TypeInferenceOracle::elementWrite(JSScript *script, jsbytecode *pc)
bool
TypeInferenceOracle::arrayPrototypeHasIndexedProperty()
{
RootedScript script(cx, script_);
return ArrayPrototypeHasIndexedProperty(cx, script);
}
bool
TypeInferenceOracle::canInlineCalls()
{
return script->analysis()->hasFunctionCalls();
return script_->analysis()->hasFunctionCalls();
}
bool
@ -502,10 +503,10 @@ TypeInferenceOracle::elementWriteNeedsBarrier(JSScript *script, jsbytecode *pc)
StackTypeSet *
TypeInferenceOracle::getCallTarget(JSScript *caller, uint32 argc, jsbytecode *pc)
{
JS_ASSERT(caller == this->script);
JS_ASSERT(caller == this->script_);
JS_ASSERT(js_CodeSpec[*pc].format & JOF_INVOKE && JSOp(*pc) != JSOP_EVAL);
ScriptAnalysis *analysis = script->analysis();
ScriptAnalysis *analysis = script_->analysis();
return analysis->poppedTypes(pc, argc + 1);
}

View File

@ -213,13 +213,13 @@ class DummyOracle : public TypeOracle
class TypeInferenceOracle : public TypeOracle
{
JSContext *cx;
JSScript *script;
HeapPtrScript script_;
MIRType getMIRType(types::StackTypeSet *types);
MIRType getMIRType(types::HeapTypeSet *types);
public:
TypeInferenceOracle() : cx(NULL), script(NULL) {}
TypeInferenceOracle() : cx(NULL), script_(NULL) {}
bool init(JSContext *cx, JSScript *script);

View File

@ -8,6 +8,8 @@
#include "ion/IonMacroAssembler.h"
#include "gc/Marking.h"
#include "jsscriptinlines.h"
using namespace js;
using namespace js::ion;

View File

@ -7,6 +7,8 @@
#include "MoveEmitter-x86-shared.h"
#include "jsscriptinlines.h"
using namespace js;
using namespace js::ion;

View File

@ -8,6 +8,8 @@
#include "Assembler-x64.h"
#include "gc/Marking.h"
#include "jsscriptinlines.h"
using namespace js;
using namespace js::ion;

View File

@ -9,6 +9,8 @@
#include "ion/MoveEmitter.h"
#include "ion/IonFrames.h"
#include "jsscriptinlines.h"
using namespace js;
using namespace js::ion;

View File

@ -14,6 +14,8 @@
#include "ion/VMFunctions.h"
#include "ion/IonSpewer.h"
#include "jsscriptinlines.h"
using namespace js;
using namespace js::ion;

View File

@ -0,0 +1,8 @@
Object.defineProperty(Object.prototype, 'x', {
set: function() {}
});
var obj = {};
for (var i = 0; i < 100 ; ++i) {
obj.x = 1;
delete obj.x;
}

View File

@ -0,0 +1,8 @@
try {
__defineGetter__("eval", function() {
this["__proto__"]
})
delete this["__proto__"]
this["__proto__"]
} catch (e) {}
eval

View File

@ -55,7 +55,7 @@ ScriptAnalysis::addJump(JSContext *cx, unsigned offset,
unsigned *currentOffset, unsigned *forwardJump, unsigned *forwardLoop,
unsigned stackDepth)
{
JS_ASSERT(offset < script->length);
JS_ASSERT(offset < script_->length);
Bytecode *&code = codeArray[offset];
if (!code) {
@ -111,9 +111,9 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
JS_ASSERT(!ranBytecode());
LifoAlloc &alloc = cx->analysisLifoAlloc();
numSlots = TotalSlots(script);
numSlots = TotalSlots(script_);
unsigned length = script->length;
unsigned length = script_->length;
codeArray = alloc.newArray<Bytecode*>(length);
escapedSlots = alloc.newArray<bool>(numSlots);
@ -138,14 +138,14 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
PodZero(escapedSlots, numSlots);
bool allVarsAliased = script->compartment()->debugMode();
bool allArgsAliased = allVarsAliased || script->argumentsHasVarBinding();
bool allVarsAliased = script_->compartment()->debugMode();
bool allArgsAliased = allVarsAliased || script_->argumentsHasVarBinding();
for (BindingIter bi(script->bindings); bi; bi++) {
for (BindingIter bi(script_->bindings); bi; bi++) {
if (bi->kind() == ARGUMENT)
escapedSlots[ArgSlot(bi.frameIndex())] = allArgsAliased || bi->aliased();
else
escapedSlots[LocalSlot(script, bi.frameIndex())] = allVarsAliased || bi->aliased();
escapedSlots[LocalSlot(script_, bi.frameIndex())] = allVarsAliased || bi->aliased();
}
/*
@ -155,12 +155,12 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
if (cx->compartment->debugMode())
usesReturnValue_ = true;
bool heavyweight = script->function() && script->function()->isHeavyweight();
bool heavyweight = script_->function() && script_->function()->isHeavyweight();
isJaegerCompileable = true;
isInlineable = true;
if (heavyweight || script->argumentsHasVarBinding() || cx->compartment->debugMode())
if (heavyweight || script_->argumentsHasVarBinding() || cx->compartment->debugMode())
isInlineable = false;
modifiesArguments_ = false;
@ -197,7 +197,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
/* Number of JOF_TYPESET opcodes we have encountered. */
unsigned nTypeSets = 0;
types::TypeSet *typeArray = script->types->typeArray();
types::TypeSet *typeArray = script_->types->typeArray();
unsigned offset, nextOffset = 0;
while (nextOffset < length) {
@ -212,7 +212,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
forwardCatch = 0;
Bytecode *code = maybeCode(offset);
jsbytecode *pc = script->code + offset;
jsbytecode *pc = script_->code + offset;
JSOp op = (JSOp)*pc;
JS_ASSERT(op < JSOP_LIMIT);
@ -251,7 +251,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
if (forwardCatch)
code->inTryBlock = true;
if (script->hasBreakpointsAt(pc)) {
if (script_->hasBreakpointsAt(pc)) {
code->safePoint = true;
isInlineable = canTrackVars = false;
}
@ -266,8 +266,8 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
* pick up the stack depths as we go through the decomposed version.
*/
if (!(js_CodeSpec[op].format & JOF_DECOMPOSE)) {
unsigned nuses = GetUseCount(script, offset);
unsigned ndefs = GetDefCount(script, offset);
unsigned nuses = GetUseCount(script_, offset);
unsigned ndefs = GetDefCount(script_, offset);
JS_ASSERT(stackDepth >= nuses);
stackDepth -= nuses;
@ -282,7 +282,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
* used for the observed types of all ops after the overflow.
*/
if ((js_CodeSpec[op].format & JOF_TYPESET) && cx->typeInferenceEnabled()) {
if (nTypeSets < script->nTypeSets) {
if (nTypeSets < script_->nTypeSets) {
code->observedTypes = typeArray[nTypeSets++].toStackTypeSet();
} else {
JS_ASSERT(nTypeSets == UINT16_MAX);
@ -413,10 +413,10 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
* no more code will execute, and it does not matter what is defined.
*/
isInlineable = false;
JSTryNote *tn = script->trynotes()->vector;
JSTryNote *tnlimit = tn + script->trynotes()->length;
JSTryNote *tn = script_->trynotes()->vector;
JSTryNote *tnlimit = tn + script_->trynotes()->length;
for (; tn < tnlimit; tn++) {
unsigned startOffset = script->mainOffset + tn->start;
unsigned startOffset = script_->mainOffset + tn->start;
if (startOffset == offset + 1) {
unsigned catchOffset = startOffset + tn->length;
@ -444,7 +444,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
jsbytecode *next = pc + JSOP_GETLOCAL_LENGTH;
if (JSOp(*next) != JSOP_POP || jumpTarget(next)) {
uint32_t local = GET_SLOTNO(pc);
if (local >= script->nfixed) {
if (local >= script_->nfixed) {
localsAliasStack_ = true;
break;
}
@ -459,7 +459,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
case JSOP_LOCALDEC:
case JSOP_SETLOCAL: {
uint32_t local = GET_SLOTNO(pc);
if (local >= script->nfixed) {
if (local >= script_->nfixed) {
localsAliasStack_ = true;
break;
}
@ -614,7 +614,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
/* Handle any fallthrough from this opcode. */
if (!BytecodeNoFallThrough(op)) {
JS_ASSERT(successorOffset < script->length);
JS_ASSERT(successorOffset < script_->length);
Bytecode *&nextcode = codeArray[successorOffset];
@ -649,7 +649,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
* entering the script. This allows the functionPrologue to ensure that
* arguments are always created eagerly which simplifies interp logic.
*/
if (!script->analyzedArgsUsage())
if (!script_->analyzedArgsUsage())
analyzeSSA(cx);
/*
@ -662,7 +662,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
mjit::JITScript *jit = NULL;
for (int constructing = 0; constructing <= 1 && !jit; constructing++) {
for (int barriers = 0; barriers <= 1 && !jit; barriers++)
jit = script->getJIT((bool) constructing, (bool) barriers);
jit = script_->getJIT((bool) constructing, (bool) barriers);
}
if (jit) {
mjit::CrossChunkEdge *edges = jit->edges();
@ -709,8 +709,8 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
LoopAnalysis *loop = NULL;
uint32_t offset = script->length - 1;
while (offset < script->length) {
uint32_t offset = script_->length - 1;
while (offset < script_->length) {
Bytecode *code = maybeCode(offset);
if (!code) {
offset--;
@ -720,7 +720,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
if (loop && code->safePoint)
loop->hasSafePoints = true;
jsbytecode *pc = script->code + offset;
jsbytecode *pc = script_->code + offset;
JSOp op = (JSOp) *pc;
@ -748,10 +748,10 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
if (code->exceptionEntry) {
DebugOnly<bool> found = false;
JSTryNote *tn = script->trynotes()->vector;
JSTryNote *tnlimit = tn + script->trynotes()->length;
JSTryNote *tn = script_->trynotes()->vector;
JSTryNote *tnlimit = tn + script_->trynotes()->length;
for (; tn < tnlimit; tn++) {
unsigned startOffset = script->mainOffset + tn->start;
unsigned startOffset = script_->mainOffset + tn->start;
if (startOffset + tn->length == offset) {
/*
* Extend all live variables at exception entry to the start of
@ -775,7 +775,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
case JSOP_GETLOCAL:
case JSOP_CALLLOCAL:
case JSOP_THIS: {
uint32_t slot = GetBytecodeSlot(script, pc);
uint32_t slot = GetBytecodeSlot(script_, pc);
if (!slotEscapes(slot))
addVariable(cx, lifetimes[slot], offset, saved, savedCount);
break;
@ -783,7 +783,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
case JSOP_SETARG:
case JSOP_SETLOCAL: {
uint32_t slot = GetBytecodeSlot(script, pc);
uint32_t slot = GetBytecodeSlot(script_, pc);
if (!slotEscapes(slot))
killVariable(cx, lifetimes[slot], offset, saved, savedCount);
break;
@ -797,7 +797,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
case JSOP_DECLOCAL:
case JSOP_LOCALINC:
case JSOP_LOCALDEC: {
uint32_t slot = GetBytecodeSlot(script, pc);
uint32_t slot = GetBytecodeSlot(script_, pc);
if (!slotEscapes(slot)) {
killVariable(cx, lifetimes[slot], offset, saved, savedCount);
addVariable(cx, lifetimes[slot], offset, saved, savedCount);
@ -855,7 +855,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
* their target offset --- the variables live before the jump are
* the union of those live at the fallthrough and at the target.
*/
uint32_t targetOffset = FollowBranch(cx, script, offset);
uint32_t targetOffset = FollowBranch(cx, script_, offset);
/*
* Watch for 'continue' statements in the loop body, which are
@ -868,7 +868,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
/* This is a loop back edge, no lifetime to pull in yet. */
#ifdef DEBUG
JSOp nop = JSOp(script->code[targetOffset]);
JSOp nop = JSOp(script_->code[targetOffset]);
JS_ASSERT(nop == JSOP_LOOPHEAD);
#endif
@ -911,7 +911,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
entry--;
} while (!maybeCode(entry));
jsbytecode *entrypc = script->code + entry;
jsbytecode *entrypc = script_->code + entry;
if (JSOp(*entrypc) == JSOP_GOTO || JSOp(*entrypc) == JSOP_FILTER)
loop->entry = entry + GET_JUMP_OFFSET(entrypc);
@ -921,8 +921,8 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
/* Do-while loop at the start of the script. */
loop->entry = targetOffset;
}
JS_ASSERT(script->code[loop->entry] == JSOP_LOOPHEAD ||
script->code[loop->entry] == JSOP_LOOPENTRY);
JS_ASSERT(script_->code[loop->entry] == JSOP_LOOPHEAD ||
script_->code[loop->entry] == JSOP_LOOPENTRY);
} else {
for (unsigned i = 0; i < savedCount; i++) {
LifetimeVariable &var = *saved[i];
@ -1186,7 +1186,7 @@ ScriptAnalysis::clearAllocations()
* that compilation has finished. Register allocations are only used for
* a single compilation.
*/
for (unsigned i = 0; i < script->length; i++) {
for (unsigned i = 0; i < script_->length; i++) {
Bytecode *code = maybeCode(i);
if (code)
code->allocation = NULL;
@ -1209,7 +1209,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
}
LifoAlloc &alloc = cx->analysisLifoAlloc();
unsigned maxDepth = script->nslots - script->nfixed;
unsigned maxDepth = script_->nslots - script_->nfixed;
/*
* Current value of each variable and stack value. Empty for missing or
@ -1251,8 +1251,8 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
Vector<uint32_t> exceptionTargets(cx);
uint32_t offset = 0;
while (offset < script->length) {
jsbytecode *pc = script->code + offset;
while (offset < script_->length) {
jsbytecode *pc = script_->code + offset;
JSOp op = (JSOp)*pc;
uint32_t successorOffset = offset + GetBytecodeLength(pc);
@ -1384,8 +1384,8 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
continue;
}
unsigned nuses = GetUseCount(script, offset);
unsigned ndefs = GetDefCount(script, offset);
unsigned nuses = GetUseCount(script_, offset);
unsigned ndefs = GetDefCount(script_, offset);
JS_ASSERT(stackDepth >= nuses);
unsigned xuses = ExtendedUse(pc) ? nuses + 1 : nuses;
@ -1406,7 +1406,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
* For SETLOCAL, INCLOCAL, etc. opcodes, add an extra popped
* value holding the value of the local before the op.
*/
uint32_t slot = GetBytecodeSlot(script, pc);
uint32_t slot = GetBytecodeSlot(script_, pc);
if (trackSlot(slot))
code->poppedValues[nuses] = values[slot].v;
else
@ -1452,7 +1452,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
stackDepth += ndefs;
if (BytecodeUpdatesSlot(op)) {
uint32_t slot = GetBytecodeSlot(script, pc);
uint32_t slot = GetBytecodeSlot(script_, pc);
if (trackSlot(slot)) {
mergeBranchTarget(cx, values[slot], slot, branchTargets, offset);
mergeExceptionTarget(cx, values[slot].v, slot, exceptionTargets);
@ -1463,7 +1463,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
switch (op) {
case JSOP_GETARG:
case JSOP_GETLOCAL: {
uint32_t slot = GetBytecodeSlot(script, pc);
uint32_t slot = GetBytecodeSlot(script_, pc);
if (trackSlot(slot)) {
/*
* Propagate the current value of the local to the pushed value,
@ -1555,10 +1555,10 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
}
case JSOP_TRY: {
JSTryNote *tn = script->trynotes()->vector;
JSTryNote *tnlimit = tn + script->trynotes()->length;
JSTryNote *tn = script_->trynotes()->vector;
JSTryNote *tnlimit = tn + script_->trynotes()->length;
for (; tn < tnlimit; tn++) {
unsigned startOffset = script->mainOffset + tn->start;
unsigned startOffset = script_->mainOffset + tn->start;
if (startOffset == offset + 1) {
unsigned catchOffset = startOffset + tn->length;
@ -1582,7 +1582,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
}
if (IsJumpOpcode(op)) {
unsigned targetOffset = FollowBranch(cx, script, offset);
unsigned targetOffset = FollowBranch(cx, script_, offset);
checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth);
/*
@ -1602,8 +1602,8 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
* Now that we have full SSA information for the script, analyze whether
* we can avoid creating the arguments object.
*/
if (!script->analyzedArgsUsage())
script->setNeedsArgsObj(needsArgsObj(cx));
if (!script_->analyzedArgsUsage())
script_->setNeedsArgsObj(needsArgsObj(cx));
}
/* Get a phi node's capacity for a given length. */
@ -1755,7 +1755,7 @@ ScriptAnalysis::checkBranchTarget(JSContext *cx, uint32_t targetOffset,
* pushing values in each opcode.
*/
for (unsigned i = 0; i < targetDepth; i++) {
uint32_t slot = StackSlot(script, i);
uint32_t slot = StackSlot(script_, i);
checkPendingValue(cx, values[slot].v, slot, pending);
}
}
@ -1922,7 +1922,7 @@ ScriptAnalysis::needsArgsObj(JSContext *cx, SeenVector &seen, SSAUseChain *use)
if (!use->popped)
return needsArgsObj(cx, seen, SSAValue::PhiValue(use->offset, use->u.phi));
jsbytecode *pc = script->code + use->offset;
jsbytecode *pc = script_->code + use->offset;
JSOp op = JSOp(*pc);
if (op == JSOP_POP || op == JSOP_POPN)
@ -1947,7 +1947,7 @@ ScriptAnalysis::needsArgsObj(JSContext *cx, SeenVector &seen, SSAUseChain *use)
/* Allow assignments to non-closed locals (but not arguments). */
if (op == JSOP_SETLOCAL) {
uint32_t slot = GetBytecodeSlot(script, pc);
uint32_t slot = GetBytecodeSlot(script_, pc);
if (!trackSlot(slot))
return true;
return needsArgsObj(cx, seen, SSAValue::PushedValue(use->offset, 0)) ||
@ -1963,20 +1963,20 @@ ScriptAnalysis::needsArgsObj(JSContext *cx, SeenVector &seen, SSAUseChain *use)
bool
ScriptAnalysis::needsArgsObj(JSContext *cx)
{
JS_ASSERT(script->argumentsHasVarBinding());
JS_ASSERT(script_->argumentsHasVarBinding());
/*
* Since let variables and dynamic name access are not tracked, we cannot
* soundly perform this analysis in their presence. Generators can be
* suspended when the speculation fails, so disallow it also.
*/
if (script->bindingsAccessedDynamically || script->funHasAnyAliasedFormal ||
localsAliasStack() || cx->compartment->debugMode() || script->isGenerator)
if (script_->bindingsAccessedDynamically || script_->funHasAnyAliasedFormal ||
localsAliasStack() || cx->compartment->debugMode() || script_->isGenerator)
{
return true;
}
unsigned pcOff = script->argumentsBytecode() - script->code;
unsigned pcOff = script_->argumentsBytecode() - script_->code;
SeenVector seen(cx);
return needsArgsObj(cx, seen, SSAValue::PushedValue(pcOff, 0));
@ -2073,14 +2073,14 @@ ScriptAnalysis::printSSA(JSContext *cx)
printf("\n");
for (unsigned offset = 0; offset < script->length; offset++) {
for (unsigned offset = 0; offset < script_->length; offset++) {
Bytecode *code = maybeCode(offset);
if (!code)
continue;
jsbytecode *pc = script->code + offset;
jsbytecode *pc = script_->code + offset;
PrintBytecode(cx, script, pc);
PrintBytecode(cx, script_, pc);
SlotValue *newv = code->newValues;
if (newv) {
@ -2102,7 +2102,7 @@ ScriptAnalysis::printSSA(JSContext *cx)
}
}
unsigned nuses = GetUseCount(script, offset);
unsigned nuses = GetUseCount(script_, offset);
unsigned xuses = ExtendedUse(pc) ? nuses + 1 : nuses;
for (unsigned i = 0; i < xuses; i++) {
@ -2147,7 +2147,7 @@ SSAValue::print() const
void
ScriptAnalysis::assertMatchingDebugMode()
{
JS_ASSERT(!!script->compartment()->debugMode() == !!originalDebugMode_);
JS_ASSERT(!!script_->compartment()->debugMode() == !!originalDebugMode_);
}
#endif /* DEBUG */

View File

@ -839,7 +839,7 @@ class ScriptAnalysis
{
friend class Bytecode;
JSScript *script;
JSScript *script_;
Bytecode **codeArray;
@ -885,9 +885,9 @@ class ScriptAnalysis
ScriptAnalysis(JSScript *script) {
PodZero(this);
this->script = script;
this->script_ = script;
#ifdef DEBUG
this->originalDebugMode_ = script->compartment()->debugMode();
this->originalDebugMode_ = script_->compartment()->debugMode();
#endif
}
@ -907,7 +907,7 @@ class ScriptAnalysis
bool OOM() const { return outOfMemory; }
bool failed() const { return hadFailure; }
bool inlineable() const { return isInlineable; }
bool inlineable(uint32_t argc) const { return isInlineable && argc == script->function()->nargs; }
bool inlineable(uint32_t argc) const { return isInlineable && argc == script_->function()->nargs; }
bool jaegerCompileable() { return isJaegerCompileable; }
/* Number of property read opcodes in the script. */
@ -933,30 +933,30 @@ class ScriptAnalysis
/*
* True if there are any LOCAL opcodes aliasing values on the stack (above
* script->nfixed).
* script_->nfixed).
*/
bool localsAliasStack() { return localsAliasStack_; }
/* Accessors for bytecode information. */
Bytecode& getCode(uint32_t offset) {
JS_ASSERT(offset < script->length);
JS_ASSERT(offset < script_->length);
JS_ASSERT(codeArray[offset]);
return *codeArray[offset];
}
Bytecode& getCode(const jsbytecode *pc) { return getCode(pc - script->code); }
Bytecode& getCode(const jsbytecode *pc) { return getCode(pc - script_->code); }
Bytecode* maybeCode(uint32_t offset) {
JS_ASSERT(offset < script->length);
JS_ASSERT(offset < script_->length);
return codeArray[offset];
}
Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(pc - script->code); }
Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(pc - script_->code); }
bool jumpTarget(uint32_t offset) {
JS_ASSERT(offset < script->length);
JS_ASSERT(offset < script_->length);
return codeArray[offset] && codeArray[offset]->jumpTarget;
}
bool jumpTarget(const jsbytecode *pc) { return jumpTarget(pc - script->code); }
bool jumpTarget(const jsbytecode *pc) { return jumpTarget(pc - script_->code); }
bool popGuaranteed(jsbytecode *pc) {
jsbytecode *next = pc + GetBytecodeLength(pc);
@ -974,31 +974,31 @@ class ScriptAnalysis
}
const SSAValue &poppedValue(uint32_t offset, uint32_t which) {
JS_ASSERT(offset < script->length);
JS_ASSERT(which < GetUseCount(script, offset) +
(ExtendedUse(script->code + offset) ? 1 : 0));
JS_ASSERT(offset < script_->length);
JS_ASSERT(which < GetUseCount(script_, offset) +
(ExtendedUse(script_->code + offset) ? 1 : 0));
return getCode(offset).poppedValues[which];
}
const SSAValue &poppedValue(const jsbytecode *pc, uint32_t which) {
return poppedValue(pc - script->code, which);
return poppedValue(pc - script_->code, which);
}
const SlotValue *newValues(uint32_t offset) {
JS_ASSERT(offset < script->length);
JS_ASSERT(offset < script_->length);
return getCode(offset).newValues;
}
const SlotValue *newValues(const jsbytecode *pc) { return newValues(pc - script->code); }
const SlotValue *newValues(const jsbytecode *pc) { return newValues(pc - script_->code); }
types::StackTypeSet *pushedTypes(uint32_t offset, uint32_t which = 0) {
JS_ASSERT(offset < script->length);
JS_ASSERT(which < GetDefCount(script, offset) +
(ExtendedDef(script->code + offset) ? 1 : 0));
JS_ASSERT(offset < script_->length);
JS_ASSERT(which < GetDefCount(script_, offset) +
(ExtendedDef(script_->code + offset) ? 1 : 0));
types::StackTypeSet *array = getCode(offset).pushedTypes;
JS_ASSERT(array);
return array + which;
}
types::StackTypeSet *pushedTypes(const jsbytecode *pc, uint32_t which) {
return pushedTypes(pc - script->code, which);
return pushedTypes(pc - script_->code, which);
}
bool hasPushedTypes(const jsbytecode *pc) { return getCode(pc).pushedTypes != NULL; }
@ -1009,7 +1009,7 @@ class ScriptAnalysis
return getCode(offset).typeBarriers;
}
types::TypeBarrier *typeBarriers(JSContext *cx, const jsbytecode *pc) {
return typeBarriers(cx, pc - script->code);
return typeBarriers(cx, pc - script_->code);
}
void addTypeBarrier(JSContext *cx, const jsbytecode *pc,
types::TypeSet *target, types::Type type);
@ -1038,7 +1038,7 @@ class ScriptAnalysis
case SSAValue::VAR:
JS_ASSERT(!slotEscapes(v.varSlot()));
if (v.varInitial()) {
return types::TypeScript::SlotTypes(script, v.varSlot());
return types::TypeScript::SlotTypes(script_, v.varSlot());
} else {
/*
* Results of intermediate assignments have the same type as
@ -1082,31 +1082,31 @@ class ScriptAnalysis
if (v.kind() == SSAValue::PUSHED)
return getCode(v.pushedOffset()).pushedUses[v.pushedIndex()];
if (v.kind() == SSAValue::VAR)
return getCode(v.varOffset()).pushedUses[GetDefCount(script, v.varOffset())];
return getCode(v.varOffset()).pushedUses[GetDefCount(script_, v.varOffset())];
return v.phiNode()->uses;
}
mjit::RegisterAllocation *&getAllocation(uint32_t offset) {
JS_ASSERT(offset < script->length);
JS_ASSERT(offset < script_->length);
return getCode(offset).allocation;
}
mjit::RegisterAllocation *&getAllocation(const jsbytecode *pc) {
return getAllocation(pc - script->code);
return getAllocation(pc - script_->code);
}
LoopAnalysis *getLoop(uint32_t offset) {
JS_ASSERT(offset < script->length);
JS_ASSERT(offset < script_->length);
return getCode(offset).loop;
}
LoopAnalysis *getLoop(const jsbytecode *pc) { return getLoop(pc - script->code); }
LoopAnalysis *getLoop(const jsbytecode *pc) { return getLoop(pc - script_->code); }
/* For a JSOP_CALL* op, get the pc of the corresponding JSOP_CALL/NEW/etc. */
jsbytecode *getCallPC(jsbytecode *pc)
{
SSAUseChain *uses = useChain(SSAValue::PushedValue(pc - script->code, 0));
SSAUseChain *uses = useChain(SSAValue::PushedValue(pc - script_->code, 0));
JS_ASSERT(uses && uses->popped);
JS_ASSERT(js_CodeSpec[script->code[uses->offset]].format & JOF_INVOKE);
return script->code + uses->offset;
JS_ASSERT(js_CodeSpec[script_->code[uses->offset]].format & JOF_INVOKE);
return script_->code + uses->offset;
}
/* Accessors for local variable information. */
@ -1119,7 +1119,7 @@ class ScriptAnalysis
* containing script (which does not imply the variable is closed).
*/
bool slotEscapes(uint32_t slot) {
JS_ASSERT(script->compartment()->activeAnalysis);
JS_ASSERT(script_->compartment()->activeAnalysis);
if (slot >= numSlots)
return true;
return escapedSlots[slot];
@ -1134,7 +1134,7 @@ class ScriptAnalysis
bool trackSlot(uint32_t slot) { return !slotEscapes(slot) && canTrackVars && slot < 1000; }
const LifetimeVariable & liveness(uint32_t slot) {
JS_ASSERT(script->compartment()->activeAnalysis);
JS_ASSERT(script_->compartment()->activeAnalysis);
JS_ASSERT(!slotEscapes(slot));
return lifetimes[slot];
}

View File

@ -580,7 +580,7 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI);
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
RawScript script = i.get<JSScript>();
if (script->types) {
types::TypeScript::Sweep(fop, script);

View File

@ -959,44 +959,47 @@ InFreeList(ArenaHeader *aheader, uintptr_t addr)
}
#ifdef JSGC_USE_EXACT_ROOTING
static inline void
MarkExactStackRooter(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind)
{
void **addr = (void **)rooter->address();
if (!*addr)
return;
switch (kind) {
case THING_ROOT_OBJECT: MarkObjectRoot(trc, (JSObject **)addr, "exact-object"); break;
case THING_ROOT_STRING: MarkStringRoot(trc, (JSSTring **)addr, "exact-string"); break;
case THING_ROOT_SCRIPT: MarkScriptRoot(trc, (JSScript **)addr, "exact-script"); break;
case THING_ROOT_SHAPE: MarkShapeRoot(trc, (Shape **)addr, "exact-shape"); break;
case THING_ROOT_BASE_SHAPE: MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact-baseshape"); break;
case THING_ROOT_TYPE: MarkTypeRoot(trc, (types::Type *)addr, "exact-type"); break;
case THING_ROOT_TYPE_OBJECT: MarkTypeObjectRoot(trc, (types::TypeObject **)addr, "exact-typeobject"); break;
case THING_ROOT_VALUE: MarkValueRoot(trc, (Value *)addr, "exact-value"); break;
case THING_ROOT_ID: MarkIdRoot(trc, (jsid *)addr, "exact-id"); break;
case THING_ROOT_PROPERTY_ID: MarkIdRoot(trc, &((js::PropertyId *)addr)->asId(), "exact-propertyid"); break;
case THING_ROOT_BINDINGS: ((Bindings *)addr)->trace(trc); break;
default: JS_NOT_REACHED("Invalid THING_ROOT kind"); break;
}
}
static inline void
MarkExactStackRooters(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind)
{
Rooted<void*> *rooter = cx->thingGCRooters[i];
while (rooter) {
MarkExactStackRoot(trc, rooter, ThingRootKind(i));
rooter = rooter->previous();
}
}
static void
MarkExactStackRoots(JSTracer *trc)
{
for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
Rooted<void*> *rooter = cx->thingGCRooters[i];
while (rooter) {
void **addr = (void **)rooter->address();
if (*addr) {
if (i == THING_ROOT_OBJECT) {
MarkObjectRoot(trc, (JSObject **)addr, "exact stackroot object");
} else if (i == THING_ROOT_STRING) {
MarkStringRoot(trc, (JSString **)addr, "exact stackroot string");
} else if (i == THING_ROOT_ID) {
MarkIdRoot(trc, (jsid *)addr, "exact stackroot id");
} else if (i == THING_ROOT_PROPERTY_ID) {
MarkIdRoot(trc, &((PropertyId *)addr)->asId(), "exact stackroot property id");
} else if (i == THING_ROOT_VALUE) {
MarkValueRoot(trc, (Value *)addr, "exact stackroot value");
} else if (i == THING_ROOT_TYPE) {
MarkTypeRoot(trc, (types::Type *)addr, "exact stackroot type");
} else if (i == THING_ROOT_SHAPE) {
MarkShapeRoot(trc, (Shape **)addr, "exact stackroot shape");
} else if (i == THING_ROOT_BASE_SHAPE) {
MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact stackroot baseshape");
} else if (i == THING_ROOT_TYPE_OBJECT) {
MarkTypeObjectRoot(trc, (types::TypeObject **)addr, "exact stackroot typeobject");
} else if (i == THING_ROOT_SCRIPT) {
MarkScriptRoot(trc, (JSScript **)addr, "exact stackroot script");
} else if (i == THING_ROOT_XML) {
MarkXMLRoot(trc, (JSXML **)addr, "exact stackroot xml");
} else {
JS_NOT_REACHED("Invalid thing root kind.");
}
}
rooter = rooter->previous();
}
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
MarkExactStackRooters(trc, cx->thingGCRooters[i], ThingRootKind(i));
}
MarkExactStackRooters(trc, rt->thingGCRooters[i], ThingRootKind(i));
}
}
#endif /* JSGC_USE_EXACT_ROOTING */
@ -4970,11 +4973,21 @@ SetValidateGC(JSContext *cx, bool enabled)
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
JS_ALWAYS_INLINE bool
CheckStackRootThing(uintptr_t *w, void *address, ThingRootKind kind)
{
if (kind != THING_ROOT_BINDINGS)
return address == static_cast<void*>(w);
Bindings *bp = static_cast<Bindings*>(address);
return w >= (uintptr_t*)bp && w < (uintptr_t*)(bp + 1);
}
JS_ALWAYS_INLINE void
CheckStackRootThings(uintptr_t *w, Rooted<void*> *rooter, bool *matched)
CheckStackRootThings(uintptr_t *w, Rooted<void*> *rooter, ThingRootKind kind, bool *matched)
{
while (rooter) {
if (rooter->address() == static_cast<void*>(w))
if (CheckStackRootThing(w, rooter->address(), kind))
*matched = true;
rooter = rooter->previous();
}
@ -4994,9 +5007,9 @@ CheckStackRoot(JSTracer *trc, uintptr_t *w)
bool matched = false;
JSRuntime *rt = trc->runtime;
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
CheckStackRootThings(w, rt->thingGCRooters[i], &matched);
CheckStackRootThings(w, rt->thingGCRooters[i], ThingRootKind(i), &matched);
for (ContextIter cx(rt); !cx.done(); cx.next()) {
CheckStackRootThings(w, cx->thingGCRooters[i], &matched);
CheckStackRootThings(w, cx->thingGCRooters[i], ThingRootKind(i), &matched);
SkipRoot *skip = cx->skipGCRooters;
while (skip) {
if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w)))

File diff suppressed because it is too large Load Diff

View File

@ -540,19 +540,19 @@ class StackTypeSet : public TypeSet
/* Constraints for type inference. */
void addSubset(JSContext *cx, TypeSet *target);
void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
void addGetProperty(JSContext *cx, HandleScript script, jsbytecode *pc,
StackTypeSet *target, jsid id);
void addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
void addSetProperty(JSContext *cx, HandleScript script, jsbytecode *pc,
StackTypeSet *target, jsid id);
void addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
void addSetElement(JSContext *cx, HandleScript script, jsbytecode *pc,
StackTypeSet *objectTypes, StackTypeSet *valueTypes);
void addCall(JSContext *cx, TypeCallsite *site);
void addArith(JSContext *cx, JSScript *script, jsbytecode *pc,
void addArith(JSContext *cx, HandleScript script, jsbytecode *pc,
TypeSet *target, TypeSet *other = NULL);
void addTransformThis(JSContext *cx, JSScript *script, TypeSet *target);
void addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc,
void addTransformThis(JSContext *cx, HandleScript script, TypeSet *target);
void addPropagateThis(JSContext *cx, HandleScript script, jsbytecode *pc,
Type type, StackTypeSet *types = NULL);
void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
void addSubsetBarrier(JSContext *cx, HandleScript script, jsbytecode *pc, TypeSet *target);
/*
* Constraints for JIT compilation.
@ -606,18 +606,17 @@ class HeapTypeSet : public TypeSet
/* Constraints for type inference. */
void addSubset(JSContext *cx, TypeSet *target);
void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
void addGetProperty(JSContext *cx, HandleScript script, jsbytecode *pc,
StackTypeSet *target, jsid id);
void addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id);
void addCallProperty(JSContext *cx, HandleScript script, jsbytecode *pc, jsid id);
void addFilterPrimitives(JSContext *cx, TypeSet *target);
void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
void addSubsetBarrier(JSContext *cx, HandleScript script, jsbytecode *pc, TypeSet *target);
/* Constraints for JIT compilation. */
/* Completely freeze the contents of this type set. */
void addFreeze(JSContext *cx);
/*
* Watch for a generic object state change on a type object. This currently
* includes reallocations of slot pointers for global objects, and changes
@ -1054,18 +1053,18 @@ typedef HashSet<ReadBarriered<TypeObject>, TypeObjectEntry, SystemAllocPolicy> T
/* Whether to use a new type object when calling 'new' at script/pc. */
bool
UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
UseNewType(JSContext *cx, HandleScript script, jsbytecode *pc);
/* Whether to use a new type object for an initializer opcode at script/pc. */
bool
UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey key);
UseNewTypeForInitializer(JSContext *cx, HandleScript script, jsbytecode *pc, JSProtoKey key);
/*
* Whether Array.prototype, or an object on its proto chain, has an
* indexed property.
*/
bool
ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script);
ArrayPrototypeHasIndexedProperty(JSContext *cx, HandleScript script);
/*
* Type information about a callsite. this is separated from the bytecode
@ -1116,36 +1115,38 @@ class TypeScript
/* Array of type type sets for variables and JOF_TYPESET ops. */
TypeSet *typeArray() { return (TypeSet *) (uintptr_t(this) + sizeof(TypeScript)); }
static inline unsigned NumTypeSets(JSScript *script);
static inline unsigned NumTypeSets(RawScript script);
static inline HeapTypeSet *ReturnTypes(JSScript *script);
static inline StackTypeSet *ThisTypes(JSScript *script);
static inline StackTypeSet *ArgTypes(JSScript *script, unsigned i);
static inline StackTypeSet *LocalTypes(JSScript *script, unsigned i);
static inline HeapTypeSet *ReturnTypes(RawScript script);
static inline StackTypeSet *ThisTypes(RawScript script);
static inline StackTypeSet *ArgTypes(RawScript script, unsigned i);
static inline StackTypeSet *LocalTypes(RawScript script, unsigned i);
/* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
static inline StackTypeSet *SlotTypes(JSScript *script, unsigned slot);
static inline StackTypeSet *SlotTypes(RawScript script, unsigned slot);
#ifdef DEBUG
/* Check that correct types were inferred for the values pushed by this bytecode. */
static void CheckBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value *sp);
static void CheckBytecode(JSContext *cx, HandleScript script, jsbytecode *pc,
const js::Value *sp);
#endif
/* Get the default 'new' object for a given standard class, per the script's global. */
static inline TypeObject *StandardType(JSContext *cx, JSScript *script, JSProtoKey kind);
static inline TypeObject *StandardType(JSContext *cx, HandleScript script, JSProtoKey kind);
/* Get a type object for an allocation site in this script. */
static inline TypeObject *InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind);
static inline TypeObject *InitObject(JSContext *cx, HandleScript script, jsbytecode *pc,
JSProtoKey kind);
/*
* Monitor a bytecode pushing a value which is not accounted for by the
* inference type constraints, such as integer overflow.
*/
static inline void MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc);
static inline void MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc);
static inline void MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc);
static inline void MonitorOverflow(JSContext *cx, HandleScript script, jsbytecode *pc);
static inline void MonitorString(JSContext *cx, HandleScript script, jsbytecode *pc);
static inline void MonitorUnknown(JSContext *cx, HandleScript script, jsbytecode *pc);
static inline void GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc);
static inline void GetPcScript(JSContext *cx, MutableHandleScript script, jsbytecode **pc);
static inline void MonitorOverflow(JSContext *cx);
static inline void MonitorString(JSContext *cx);
static inline void MonitorUnknown(JSContext *cx);
@ -1157,7 +1158,7 @@ class TypeScript
* always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
* and only look at barriers when generating JIT code for the script.
*/
static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc,
static inline void Monitor(JSContext *cx, HandleScript script, jsbytecode *pc,
const js::Value &val);
static inline void Monitor(JSContext *cx, const js::Value &rval);
@ -1165,17 +1166,19 @@ class TypeScript
static inline void MonitorAssign(JSContext *cx, HandleObject obj, jsid id);
/* Add a type for a variable in a script. */
static inline void SetThis(JSContext *cx, JSScript *script, Type type);
static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value);
static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type);
static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value);
static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type);
static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value);
static inline void SetThis(JSContext *cx, HandleScript script, Type type);
static inline void SetThis(JSContext *cx, HandleScript script, const js::Value &value);
static inline void SetLocal(JSContext *cx, HandleScript script, unsigned local, Type type);
static inline void SetLocal(JSContext *cx, HandleScript script, unsigned local,
const js::Value &value);
static inline void SetArgument(JSContext *cx, HandleScript script, unsigned arg, Type type);
static inline void SetArgument(JSContext *cx, HandleScript script, unsigned arg,
const js::Value &value);
static void AddFreezeConstraints(JSContext *cx, JSScript *script);
static void Purge(JSContext *cx, JSScript *script);
static void AddFreezeConstraints(JSContext *cx, HandleScript script);
static void Purge(JSContext *cx, HandleScript script);
static void Sweep(FreeOp *fop, JSScript *script);
static void Sweep(FreeOp *fop, RawScript script);
void destroy();
};
@ -1348,10 +1351,10 @@ struct TypeCompartment
/* Mark a script as needing recompilation once inference has finished. */
void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
void addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc);
void addPendingRecompile(JSContext *cx, HandleScript script, jsbytecode *pc);
/* Monitor future effects on a bytecode. */
void monitorBytecode(JSContext *cx, JSScript *script, uint32_t offset,
void monitorBytecode(JSContext *cx, HandleScript script, uint32_t offset,
bool returnOnly = false);
/* Mark any type set containing obj as having a generic object type. */

View File

@ -479,7 +479,7 @@ GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
{
if (cx->typeInferenceEnabled()) {
jsbytecode *pc;
JSScript *script = cx->stack.currentScript(&pc);
RootedScript script(cx, cx->stack.currentScript(&pc));
if (script)
return TypeScript::InitObject(cx, script, pc, key);
}
@ -636,14 +636,20 @@ FixObjectType(JSContext *cx, HandleObject obj)
}
/* Interface helpers for JSScript */
extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval);
extern void TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, js::types::Type type);
extern void TypeMonitorResult(JSContext *cx, HandleScript script, jsbytecode *pc,
const js::Value &rval);
extern void TypeDynamicResult(JSContext *cx, HandleScript script, jsbytecode *pc,
js::types::Type type);
inline bool
UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
{
return fp->isConstructing() && cx->typeInferenceEnabled() &&
fp->prev() && UseNewType(cx, fp->prev()->script(), fp->prevpc());
if (!fp->isConstructing() || !cx->typeInferenceEnabled() || !fp->prev())
return false;
RootedScript prevScript(cx, fp->prev()->script());
return UseNewType(cx, prevScript, fp->prevpc());
}
inline bool
@ -676,7 +682,7 @@ UseNewTypeForClone(JSFunction *fun)
* instance a singleton type and clone the underlying script.
*/
JSScript *script = fun->script();
RawScript script = fun->script();
if (script->length >= 50)
return false;
@ -705,20 +711,20 @@ UseNewTypeForClone(JSFunction *fun)
/////////////////////////////////////////////////////////////////////
/* static */ inline unsigned
TypeScript::NumTypeSets(JSScript *script)
TypeScript::NumTypeSets(RawScript script)
{
return script->nTypeSets + analyze::TotalSlots(script);
}
/* static */ inline HeapTypeSet *
TypeScript::ReturnTypes(JSScript *script)
TypeScript::ReturnTypes(RawScript script)
{
TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::CalleeSlot();
return types->toHeapTypeSet();
}
/* static */ inline StackTypeSet *
TypeScript::ThisTypes(JSScript *script)
TypeScript::ThisTypes(RawScript script)
{
TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::ThisSlot();
return types->toStackTypeSet();
@ -731,7 +737,7 @@ TypeScript::ThisTypes(JSScript *script)
*/
/* static */ inline StackTypeSet *
TypeScript::ArgTypes(JSScript *script, unsigned i)
TypeScript::ArgTypes(RawScript script, unsigned i)
{
JS_ASSERT(i < script->function()->nargs);
TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i);
@ -739,7 +745,7 @@ TypeScript::ArgTypes(JSScript *script, unsigned i)
}
/* static */ inline StackTypeSet *
TypeScript::LocalTypes(JSScript *script, unsigned i)
TypeScript::LocalTypes(RawScript script, unsigned i)
{
JS_ASSERT(i < script->nfixed);
TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, i);
@ -747,7 +753,7 @@ TypeScript::LocalTypes(JSScript *script, unsigned i)
}
/* static */ inline StackTypeSet *
TypeScript::SlotTypes(JSScript *script, unsigned slot)
TypeScript::SlotTypes(RawScript script, unsigned slot)
{
JS_ASSERT(slot < js::analyze::TotalSlots(script));
TypeSet *types = script->types->typeArray() + script->nTypeSets + slot;
@ -755,7 +761,7 @@ TypeScript::SlotTypes(JSScript *script, unsigned slot)
}
/* static */ inline TypeObject *
TypeScript::StandardType(JSContext *cx, JSScript *script, JSProtoKey key)
TypeScript::StandardType(JSContext *cx, HandleScript script, JSProtoKey key)
{
js::RootedObject proto(cx);
if (!js_GetClassPrototype(cx, key, &proto, NULL))
@ -785,7 +791,7 @@ struct AllocationSiteKey {
};
/* static */ inline TypeObject *
TypeScript::InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind)
TypeScript::InitObject(JSContext *cx, HandleScript script, jsbytecode *pc, JSProtoKey kind)
{
JS_ASSERT(!UseNewTypeForInitializer(cx, script, pc, kind));
@ -841,35 +847,35 @@ SetInitializerObjectType(JSContext *cx, HandleScript script, jsbytecode *pc, Han
}
/* static */ inline void
TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
TypeScript::Monitor(JSContext *cx, HandleScript script, jsbytecode *pc, const js::Value &rval)
{
if (cx->typeInferenceEnabled())
TypeMonitorResult(cx, script, pc, rval);
}
/* static */ inline void
TypeScript::MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc)
TypeScript::MonitorOverflow(JSContext *cx, HandleScript script, jsbytecode *pc)
{
if (cx->typeInferenceEnabled())
TypeDynamicResult(cx, script, pc, Type::DoubleType());
}
/* static */ inline void
TypeScript::MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc)
TypeScript::MonitorString(JSContext *cx, HandleScript script, jsbytecode *pc)
{
if (cx->typeInferenceEnabled())
TypeDynamicResult(cx, script, pc, Type::StringType());
}
/* static */ inline void
TypeScript::MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc)
TypeScript::MonitorUnknown(JSContext *cx, HandleScript script, jsbytecode *pc)
{
if (cx->typeInferenceEnabled())
TypeDynamicResult(cx, script, pc, Type::UnknownType());
}
/* static */ inline void
TypeScript::GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc)
TypeScript::GetPcScript(JSContext *cx, MutableHandleScript script, jsbytecode **pc)
{
#ifdef JS_ION
if (cx->fp()->beginsIonActivation()) {
@ -877,14 +883,14 @@ TypeScript::GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc)
return;
}
#endif
*script = cx->fp()->script();
script.set(cx->fp()->script());
*pc = cx->regs().pc;
}
/* static */ inline void
TypeScript::MonitorOverflow(JSContext *cx)
{
JSScript *script;
RootedScript script(cx);
jsbytecode *pc;
GetPcScript(cx, &script, &pc);
MonitorOverflow(cx, script, pc);
@ -893,7 +899,7 @@ TypeScript::MonitorOverflow(JSContext *cx)
/* static */ inline void
TypeScript::MonitorString(JSContext *cx)
{
JSScript *script;
RootedScript script(cx);
jsbytecode *pc;
GetPcScript(cx, &script, &pc);
MonitorString(cx, script, pc);
@ -902,7 +908,7 @@ TypeScript::MonitorString(JSContext *cx)
/* static */ inline void
TypeScript::MonitorUnknown(JSContext *cx)
{
JSScript *script;
RootedScript script(cx);
jsbytecode *pc;
GetPcScript(cx, &script, &pc);
MonitorUnknown(cx, script, pc);
@ -911,7 +917,7 @@ TypeScript::MonitorUnknown(JSContext *cx)
/* static */ inline void
TypeScript::Monitor(JSContext *cx, const js::Value &rval)
{
JSScript *script;
RootedScript script(cx);
jsbytecode *pc;
GetPcScript(cx, &script, &pc);
Monitor(cx, script, pc, rval);
@ -937,7 +943,7 @@ TypeScript::MonitorAssign(JSContext *cx, HandleObject obj, jsid id)
}
/* static */ inline void
TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
TypeScript::SetThis(JSContext *cx, HandleScript script, Type type)
{
if (!cx->typeInferenceEnabled())
return;
@ -959,14 +965,14 @@ TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
}
/* static */ inline void
TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value)
TypeScript::SetThis(JSContext *cx, HandleScript script, const js::Value &value)
{
if (cx->typeInferenceEnabled())
SetThis(cx, script, GetValueType(cx, value));
}
/* static */ inline void
TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type)
TypeScript::SetLocal(JSContext *cx, HandleScript script, unsigned local, Type type)
{
if (!cx->typeInferenceEnabled())
return;
@ -982,7 +988,7 @@ TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type)
}
/* static */ inline void
TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value)
TypeScript::SetLocal(JSContext *cx, HandleScript script, unsigned local, const js::Value &value)
{
if (cx->typeInferenceEnabled()) {
Type type = GetValueType(cx, value);
@ -991,7 +997,7 @@ TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::
}
/* static */ inline void
TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type)
TypeScript::SetArgument(JSContext *cx, HandleScript script, unsigned arg, Type type)
{
if (!cx->typeInferenceEnabled())
return;
@ -1007,7 +1013,7 @@ TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type
}
/* static */ inline void
TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value)
TypeScript::SetArgument(JSContext *cx, HandleScript script, unsigned arg, const js::Value &value)
{
if (cx->typeInferenceEnabled()) {
Type type = GetValueType(cx, value);

View File

@ -1048,11 +1048,13 @@ IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval)
* types of the pushed values are consistent with type inference information.
*/
static inline void
TypeCheckNextBytecode(JSContext *cx, JSScript *script, unsigned n, const FrameRegs &regs)
TypeCheckNextBytecode(JSContext *cx, JSScript *script_, unsigned n, const FrameRegs &regs)
{
#ifdef DEBUG
if (cx->typeInferenceEnabled() &&
n == GetBytecodeLength(regs.pc)) {
n == GetBytecodeLength(regs.pc))
{
RootedScript script(cx, script_);
TypeScript::CheckBytecode(cx, script, regs.pc, regs.sp);
}
#endif

View File

@ -706,7 +706,7 @@ GetObjectElementOperation(JSContext *cx, JSOp op, HandleObject obj, const Value
if (!cx->fp()->beginsIonActivation()) {
// Don't update getStringElement if called from Ion code, since
// ion::GetPcScript is expensive.
JSScript *script;
RootedScript script(cx);
jsbytecode *pc;
types::TypeScript::GetPcScript(cx, &script, &pc);
@ -809,7 +809,7 @@ SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, con
return true;
} else {
if (!cx->fp()->beginsIonActivation()) {
JSScript *script;
RootedScript script(cx);
jsbytecode *pc;
types::TypeScript::GetPcScript(cx, &script, &pc);

View File

@ -2368,8 +2368,10 @@ js_CreateThisForFunctionWithProto(JSContext *cx, HandleObject callee, JSObject *
res = NewObjectWithClassProto(cx, &ObjectClass, proto, callee->getParent(), kind);
}
if (res && cx->typeInferenceEnabled())
TypeScript::SetThis(cx, callee->toFunction()->script(), types::Type::ObjectType(res));
if (res && cx->typeInferenceEnabled()) {
RootedScript script(cx, callee->toFunction()->script());
TypeScript::SetThis(cx, script, types::Type::ObjectType(res));
}
return res;
}
@ -2398,7 +2400,7 @@ js_CreateThisForFunction(JSContext *cx, HandleObject callee, bool newType)
if (!JSObject::setSingletonType(cx, nobj))
return NULL;
JSScript *calleeScript = callee->toFunction()->script();
RootedScript calleeScript(cx, callee->toFunction()->script());
TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(nobj));
return nobj;

View File

@ -240,6 +240,7 @@ enum ThingRootKind
THING_ROOT_PROPERTY_ID,
THING_ROOT_VALUE,
THING_ROOT_TYPE,
THING_ROOT_BINDINGS,
THING_ROOT_LIMIT
};

View File

@ -93,9 +93,12 @@ Bindings::initWithTemporaryStorage(JSContext *cx, InternalHandle<Bindings*> self
JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == 2);
gc::AllocKind allocKind = gc::FINALIZE_OBJECT2_BACKGROUND;
JS_ASSERT(gc::GetGCKindSlots(allocKind) == CallObject::RESERVED_SLOTS);
self->callObjShape_ =
RootedShape initial(cx,
EmptyShape::getInitialShape(cx, &CallClass, NULL, cx->global(),
allocKind, BaseShape::VAROBJ | BaseShape::DELEGATE);
allocKind, BaseShape::VAROBJ | BaseShape::DELEGATE));
if (!initial)
return false;
self->callObjShape_.init(initial);
#ifdef DEBUG
HashSet<PropertyName *> added(cx);
@ -169,6 +172,12 @@ Bindings::clone(JSContext *cx, InternalHandle<Bindings*> self,
return true;
}
/* static */ Bindings
RootMethods<Bindings>::initial()
{
return Bindings();
}
template<XDRMode mode>
static bool
XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, unsigned numVars,
@ -2090,9 +2099,9 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
/* Bindings */
Bindings bindings;
Rooted<Bindings> bindings(cx);
InternalHandle<Bindings*> bindingsHandle =
InternalHandle<Bindings*>::fromMarkedLocation(&bindings);
InternalHandle<Bindings*>::fromMarkedLocation(bindings.address());
if (!Bindings::clone(cx, bindingsHandle, data, src))
return NULL;
@ -2610,3 +2619,4 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
{
return argsObjAliasesFormals() && !formalIsAliased(argSlot);
}

View File

@ -199,6 +199,15 @@ class Bindings
void trace(JSTracer *trc);
};
template <>
struct RootMethods<Bindings> {
static Bindings initial();
static ThingRootKind kind() { return THING_ROOT_BINDINGS; }
static bool poisoned(const Bindings &bindings) {
return IsPoisonedPtr(bindings.callObjShape());
}
};
class ScriptCounts
{
friend struct ::JSScript;

View File

@ -551,7 +551,6 @@ ArrayBufferObject::sweepAll(JSRuntime *rt)
JSObject **views = GetViewList(&buffer->asArrayBuffer());
JS_ASSERT(*views);
JSObject *nextBuffer = BufferLink(*views);
SetBufferLink(*views, UNSET_BUFFER_LINK);
// Rebuild the list of views of the ArrayBuffer, discarding dead views
JSObject *prevLiveView = NULL;
@ -566,6 +565,8 @@ ArrayBufferObject::sweepAll(JSRuntime *rt)
view = nextView;
}
*views = prevLiveView;
if (*views)
SetBufferLink(*views, UNSET_BUFFER_LINK);
buffer = nextBuffer;
}

View File

@ -39,7 +39,7 @@ js::StartOffThreadIonCompile(JSContext *cx, ion::IonBuilder *builder)
static void
FinishOffThreadIonCompile(ion::IonBuilder *builder)
{
JSCompartment *compartment = builder->script->compartment();
JSCompartment *compartment = builder->script()->compartment();
JS_ASSERT(compartment->rt->workerThreadState->isLocked());
compartment->ionCompartment()->finishedOffThreadCompilations().append(builder);
@ -67,7 +67,7 @@ js::CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script)
/* Cancel any pending entries for which processing hasn't started. */
for (size_t i = 0; i < state.ionWorklist.length(); i++) {
ion::IonBuilder *builder = state.ionWorklist[i];
if (CompiledScriptMatches(compartment, script, builder->script)) {
if (CompiledScriptMatches(compartment, script, builder->script())) {
FinishOffThreadIonCompile(builder);
state.ionWorklist[i--] = state.ionWorklist.back();
state.ionWorklist.popBack();
@ -86,7 +86,7 @@ js::CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script)
/* Cancel code generation for any completed entries. */
for (size_t i = 0; i < compilations.length(); i++) {
ion::IonBuilder *builder = compilations[i];
if (CompiledScriptMatches(compartment, script, builder->script)) {
if (CompiledScriptMatches(compartment, script, builder->script())) {
ion::FinishOffThreadBuilder(builder);
compilations[i--] = compilations.back();
compilations.popBack();
@ -261,7 +261,7 @@ WorkerThread::threadLoop()
}
ion::IonBuilder *builder = state.ionWorklist.popCopy();
ionScript = builder->script;
ionScript = builder->script();
JS_ASSERT(ionScript->ion == ION_COMPILING_SCRIPT);

File diff suppressed because it is too large Load Diff

View File

@ -406,7 +406,7 @@ private:
ActiveFrame *a;
ActiveFrame *outer;
JSScript *script;
JSScript *script_;
analyze::ScriptAnalysis *analysis;
jsbytecode *PC;

View File

@ -170,6 +170,7 @@ mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::Typ
* itself. Note that monitorOverflow will propagate the type as
* necessary if a *INC operation overflowed.
*/
RootedScript script(cx, script_);
types::TypeScript::MonitorOverflow(cx, script, PC);
return false;
}
@ -197,7 +198,7 @@ mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::Typ
* from ignored overflows are not live across points where the interpreter
* can join into JIT code (loop heads and safe points).
*/
CrossSSAValue pushv(a->inlineIndex, SSAValue::PushedValue(PC - script->code, 0));
CrossSSAValue pushv(a->inlineIndex, SSAValue::PushedValue(PC - script_->code, 0));
bool cannotOverflow = loop && loop->cannotIntegerOverflow(pushv);
bool ignoreOverflow = loop && loop->ignoreIntegerOverflow(pushv);
@ -910,6 +911,7 @@ mjit::Compiler::jsop_mod()
if (tryBinaryConstantFold(cx, frame, JSOP_MOD, lhs, rhs, &v)) {
types::TypeSet *pushed = pushedTypeSet(0);
if (!v.isInt32() && pushed && !pushed->hasType(types::Type::DoubleType())) {
RootedScript script(cx, script_);
types::TypeScript::MonitorOverflow(cx, script, PC);
return false;
}

View File

@ -703,6 +703,7 @@ mjit::Compiler::compileArrayWithLength(uint32_t argc)
return Compile_InlineAbort;
}
RootedScript script(cx, script_);
types::TypeObject *type = types::TypeScript::InitObject(cx, script, PC, JSProto_Array);
if (!type)
return Compile_Error;
@ -744,6 +745,7 @@ mjit::Compiler::compileArrayWithArgs(uint32_t argc)
if (argc > maxArraySlots)
return Compile_InlineAbort;
RootedScript script(cx, script_);
types::TypeObject *type = types::TypeScript::InitObject(cx, script, PC, JSProto_Array);
if (!type)
return Compile_Error;

View File

@ -723,7 +723,7 @@ mjit::Compiler::jsop_typeof()
JSOp op = JSOp(PC[JSOP_TYPEOF_LENGTH + JSOP_STRING_LENGTH]);
if (op == JSOP_STRICTEQ || op == JSOP_EQ || op == JSOP_STRICTNE || op == JSOP_NE) {
JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC + JSOP_TYPEOF_LENGTH));
JSAtom *atom = script_->getAtom(GET_UINT32_INDEX(PC + JSOP_TYPEOF_LENGTH));
JSRuntime *rt = cx->runtime;
JSValueType type = JSVAL_TYPE_UNKNOWN;
Assembler::Condition cond = (op == JSOP_STRICTEQ || op == JSOP_EQ)
@ -967,7 +967,7 @@ mjit::Compiler::jsop_arginc(JSOp op, uint32_t slot)
if (!analysis->incrementInitialValueObserved(PC)) {
// Before:
// After: V
if (script->argsObjAliasesFormals())
if (script_->argsObjAliasesFormals())
jsop_aliasedArg(slot, /* get = */ true);
else
frame.pushArg(slot);
@ -985,14 +985,14 @@ mjit::Compiler::jsop_arginc(JSOp op, uint32_t slot)
// Before: N+1
// After: N+1
bool popGuaranteed = analysis->popGuaranteed(PC);
if (script->argsObjAliasesFormals())
if (script_->argsObjAliasesFormals())
jsop_aliasedArg(slot, /* get = */ false, popGuaranteed);
else
frame.storeArg(slot, popGuaranteed);
} else {
// Before:
// After: V
if (script->argsObjAliasesFormals())
if (script_->argsObjAliasesFormals())
jsop_aliasedArg(slot, /* get = */ true);
else
frame.pushArg(slot);
@ -1016,7 +1016,7 @@ mjit::Compiler::jsop_arginc(JSOp op, uint32_t slot)
// Before: N N+1
// After: N N+1
if (script->argsObjAliasesFormals())
if (script_->argsObjAliasesFormals())
jsop_aliasedArg(slot, /* get = */ false, true);
else
frame.storeArg(slot, true);
@ -1219,7 +1219,7 @@ mjit::Compiler::jsop_setelem_dense()
masm.storeValue(vr, BaseIndex(slotsReg, key.reg(), masm.JSVAL_SCALE));
stubcc.leave();
OOL_STUBCALL(STRICT_VARIANT(script, stubs::SetElem), REJOIN_FALLTHROUGH);
OOL_STUBCALL(STRICT_VARIANT(script_, stubs::SetElem), REJOIN_FALLTHROUGH);
if (!hoisted)
frame.freeReg(slotsReg);
@ -1493,7 +1493,7 @@ mjit::Compiler::jsop_setelem_typed(int atype)
frame.freeReg(objReg);
stubcc.leave();
OOL_STUBCALL(STRICT_VARIANT(script, stubs::SetElem), REJOIN_FALLTHROUGH);
OOL_STUBCALL(STRICT_VARIANT(script_, stubs::SetElem), REJOIN_FALLTHROUGH);
frame.shimmy(2);
stubcc.rejoin(Changes(2));
@ -1538,8 +1538,8 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
FrameEntry *value = frame.peek(-1);
if (!IsCacheableSetElem(obj, id, value) || monitored(PC)) {
if (monitored(PC) && script == outerScript)
monitoredBytecodes.append(PC - script->code);
if (monitored(PC) && script_ == outerScript)
monitoredBytecodes.append(PC - script_->code);
jsop_setelem_slow();
return true;
@ -1697,9 +1697,9 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
stubcc.leave();
#if defined JS_POLYIC
passICAddress(&ic);
ic.slowPathCall = OOL_STUBCALL(STRICT_VARIANT(script, ic::SetElement), REJOIN_FALLTHROUGH);
ic.slowPathCall = OOL_STUBCALL(STRICT_VARIANT(script_, ic::SetElement), REJOIN_FALLTHROUGH);
#else
OOL_STUBCALL(STRICT_VARIANT(script, stubs::SetElem), REJOIN_FALLTHROUGH);
OOL_STUBCALL(STRICT_VARIANT(script_, stubs::SetElem), REJOIN_FALLTHROUGH);
#endif
ic.fastPathRejoin = masm.label();
@ -2684,13 +2684,13 @@ mjit::Compiler::jsop_initprop()
{
FrameEntry *obj = frame.peek(-2);
FrameEntry *fe = frame.peek(-1);
PropertyName *name = script->getName(GET_UINT32_INDEX(PC));
PropertyName *name = script_->getName(GET_UINT32_INDEX(PC));
RootedObject baseobj(cx, frame.extra(obj).initObject);
if (!baseobj || monitored(PC) || cx->compartment->compileBarriers()) {
if (monitored(PC) && script == outerScript)
monitoredBytecodes.append(PC - script->code);
if (monitored(PC) && script_ == outerScript)
monitoredBytecodes.append(PC - script_->code);
prepareStubCall(Uses(2));
masm.move(ImmPtr(name), Registers::ArgReg1);

View File

@ -136,7 +136,8 @@ stubs::SlowCall(VMFrame &f, uint32_t argc)
if (!InvokeKernel(f.cx, args))
THROW();
types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
RootedScript fscript(f.cx, f.script());
types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval());
}
void JS_FASTCALL
@ -146,7 +147,8 @@ stubs::SlowNew(VMFrame &f, uint32_t argc)
if (!InvokeConstructorKernel(f.cx, args))
THROW();
types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
RootedScript fscript(f.cx, f.script());
types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval());
}
static inline bool
@ -282,8 +284,9 @@ UncachedInlineCall(VMFrame &f, InitialFrameFlags initial,
bool construct = InitialFrameFlagsAreConstructing(initial);
RootedScript fscript(cx, f.script());
bool newType = construct && cx->typeInferenceEnabled() &&
types::UseNewType(cx, f.script(), f.pc());
types::UseNewType(cx, fscript, f.pc());
if (!types::TypeMonitorCall(cx, args, construct))
return false;
@ -360,8 +363,10 @@ UncachedInlineCall(VMFrame &f, InitialFrameFlags initial,
bool ok = RunScript(cx, script, cx->fp());
f.cx->stack.popInlineFrame(regs);
if (ok)
types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
if (ok) {
RootedScript fscript(cx, f.script());
types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval());
}
*pret = NULL;
return ok;
@ -389,7 +394,8 @@ stubs::UncachedNewHelper(VMFrame &f, uint32_t argc, UncachedCallResult &ucr)
} else {
if (!InvokeConstructorKernel(cx, args))
THROW();
types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
RootedScript fscript(cx, f.script());
types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval());
}
}
@ -418,7 +424,8 @@ stubs::Eval(VMFrame &f, uint32_t argc)
if (!InvokeKernel(f.cx, args))
THROW();
types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
RootedScript fscript(f.cx, f.script());
types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval());
return;
}
@ -426,7 +433,8 @@ stubs::Eval(VMFrame &f, uint32_t argc)
if (!DirectEval(f.cx, args))
THROW();
types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
RootedScript fscript(f.cx, f.script());
types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval());
}
void
@ -448,7 +456,8 @@ stubs::UncachedCallHelper(VMFrame &f, uint32_t argc, bool lowered, UncachedCallR
if (ucr.fun->isNative()) {
if (!CallJSNative(cx, ucr.fun->native(), args))
THROW();
types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
RootedScript fscript(cx, f.script());
types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval());
return;
}
}
@ -456,7 +465,8 @@ stubs::UncachedCallHelper(VMFrame &f, uint32_t argc, bool lowered, UncachedCallR
if (!InvokeKernel(f.cx, args))
THROW();
types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
RootedScript fscript(cx, f.script());
types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval());
return;
}
@ -730,8 +740,10 @@ FinishVarIncOp(VMFrame &f, RejoinState rejoin, Value ov, Value nv, Value *vp)
if (rejoin == REJOIN_POS) {
double d = ov.toNumber();
double N = (cs->format & JOF_INC) ? 1 : -1;
if (!nv.setNumber(d + N))
types::TypeScript::MonitorOverflow(cx, f.script(), f.pc());
if (!nv.setNumber(d + N)) {
RootedScript fscript(cx, f.script());
types::TypeScript::MonitorOverflow(cx, fscript, f.pc());
}
}
unsigned i = GET_SLOTNO(f.pc());
@ -762,7 +774,7 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
JSContext *cx = f.cx;
StackFrame *fp = f.regs.fp();
JSScript *script = fp->script();
RootedScript script(cx, fp->script());
jsbytecode *pc = f.regs.pc;

View File

@ -1648,7 +1648,8 @@ LoopState::definiteArrayAccess(const SSAValue &obj, const SSAValue &index)
if (objTypes->hasObjectFlags(cx, OBJECT_FLAG_NON_DENSE_ARRAY))
return false;
if (ArrayPrototypeHasIndexedProperty(cx, outerScript))
RootedScript rOuterScript(cx, outerScript);
if (ArrayPrototypeHasIndexedProperty(cx, rOuterScript))
return false;
uint32_t objSlot;

View File

@ -1061,7 +1061,8 @@ class CallCompiler : public BaseCompiler
if (!CallJSNative(cx, fun->native(), args))
THROWV(true);
types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
RootedScript fscript(cx, f.script());
types::TypeScript::Monitor(f.cx, fscript, f.pc(), args.rval());
/*
* Native stubs are not generated for inline frames. The overhead of

View File

@ -175,8 +175,10 @@ stubs::ToId(VMFrame &f)
if (!FetchElementId(f.cx, obj, idval, id.address(), idval))
THROW();
if (!idval.isInt32())
TypeScript::MonitorUnknown(f.cx, f.script(), f.pc());
if (!idval.isInt32()) {
RootedScript fscript(f.cx, f.script());
TypeScript::MonitorUnknown(f.cx, fscript, f.pc());
}
}
void JS_FASTCALL
@ -277,8 +279,10 @@ stubs::Ursh(VMFrame &f)
u >>= (j & 31);
if (!f.regs.sp[-2].setNumber(uint32_t(u)))
TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
if (!f.regs.sp[-2].setNumber(uint32_t(u))) {
RootedScript fscript(f.cx, f.script());
TypeScript::MonitorOverflow(f.cx, fscript, f.pc());
}
}
template<JSBool strict>
@ -591,7 +595,8 @@ stubs::Add(VMFrame &f)
THROW();
regs.sp[-2] = rval;
regs.sp--;
TypeScript::MonitorUnknown(cx, f.script(), f.pc());
RootedScript fscript(cx, f.script());
TypeScript::MonitorUnknown(cx, fscript, f.pc());
} else
#endif
{
@ -617,8 +622,10 @@ stubs::Add(VMFrame &f)
THROW();
regs.sp[-1].setString(rstr);
}
if (lIsObject || rIsObject)
TypeScript::MonitorString(cx, f.script(), f.pc());
if (lIsObject || rIsObject) {
RootedScript fscript(cx, f.script());
TypeScript::MonitorString(cx, fscript, f.pc());
}
goto string_concat;
} else {
@ -628,7 +635,8 @@ stubs::Add(VMFrame &f)
l += r;
if (!regs.sp[-2].setNumber(l) &&
(lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
TypeScript::MonitorOverflow(cx, f.script(), f.pc());
RootedScript fscript(cx, f.script());
TypeScript::MonitorOverflow(cx, fscript, f.pc());
}
}
}
@ -652,8 +660,10 @@ stubs::Sub(VMFrame &f)
if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
THROW();
double d = d1 - d2;
if (!regs.sp[-2].setNumber(d))
TypeScript::MonitorOverflow(cx, f.script(), f.pc());
if (!regs.sp[-2].setNumber(d)) {
RootedScript fscript(cx, f.script());
TypeScript::MonitorOverflow(cx, fscript, f.pc());
}
}
void JS_FASTCALL
@ -665,8 +675,10 @@ stubs::Mul(VMFrame &f)
if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
THROW();
double d = d1 * d2;
if (!regs.sp[-2].setNumber(d))
TypeScript::MonitorOverflow(cx, f.script(), f.pc());
if (!regs.sp[-2].setNumber(d)) {
RootedScript fscript(cx, f.script());
TypeScript::MonitorOverflow(cx, fscript, f.pc());
}
}
void JS_FASTCALL
@ -694,11 +706,14 @@ stubs::Div(VMFrame &f)
else
vp = &rt->positiveInfinityValue;
regs.sp[-2] = *vp;
TypeScript::MonitorOverflow(cx, f.script(), f.pc());
RootedScript fscript(cx, f.script());
TypeScript::MonitorOverflow(cx, fscript, f.pc());
} else {
d1 /= d2;
if (!regs.sp[-2].setNumber(d1))
TypeScript::MonitorOverflow(cx, f.script(), f.pc());
if (!regs.sp[-2].setNumber(d1)) {
RootedScript fscript(cx, f.script());
TypeScript::MonitorOverflow(cx, fscript, f.pc());
}
}
}
@ -725,7 +740,8 @@ stubs::Mod(VMFrame &f)
d1 = js_fmod(d1, d2);
regs.sp[-2].setDouble(d1);
}
TypeScript::MonitorOverflow(cx, f.script(), f.pc());
RootedScript fscript(cx, f.script());
TypeScript::MonitorOverflow(cx, fscript, f.pc());
}
}
@ -890,8 +906,10 @@ stubs::Neg(VMFrame &f)
if (!ToNumber(f.cx, f.regs.sp[-1], &d))
THROW();
d = -d;
if (!f.regs.sp[-1].setNumber(d))
TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
if (!f.regs.sp[-1].setNumber(d)) {
RootedScript fscript(f.cx, f.script());
TypeScript::MonitorOverflow(f.cx, fscript, f.pc());
}
}
void JS_FASTCALL
@ -905,8 +923,8 @@ stubs::NewInitArray(VMFrame &f, uint32_t count)
if (type) {
obj->setType(type);
} else {
RootedScript script(f.cx, f.script());
if (!SetInitializerObjectType(f.cx, script, f.pc(), obj))
RootedScript fscript(f.cx, f.script());
if (!SetInitializerObjectType(f.cx, fscript, f.pc(), obj))
THROW();
}
@ -934,8 +952,8 @@ stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
if (type) {
obj->setType(type);
} else {
RootedScript script(f.cx, f.script());
if (!SetInitializerObjectType(cx, script, f.pc(), obj))
RootedScript fscript(f.cx, f.script());
if (!SetInitializerObjectType(cx, fscript, f.pc(), obj))
THROW();
}
@ -1382,8 +1400,10 @@ stubs::Pos(VMFrame &f)
{
if (!ToNumber(f.cx, &f.regs.sp[-1]))
THROW();
if (!f.regs.sp[-1].isInt32())
TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
if (!f.regs.sp[-1].isInt32()) {
RootedScript fscript(f.cx, f.script());
TypeScript::MonitorOverflow(f.cx, fscript, f.pc());
}
}
void JS_FASTCALL
@ -1531,7 +1551,8 @@ stubs::TypeBarrierHelper(VMFrame &f, uint32_t which)
f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
}
TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
RootedScript fscript(f.cx, f.script());
TypeScript::Monitor(f.cx, fscript, f.pc(), result);
}
void JS_FASTCALL
@ -1544,7 +1565,8 @@ stubs::StubTypeHelper(VMFrame &f, int32_t which)
f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
}
TypeScript::Monitor(f.cx, f.script(), f.pc(), result);
RootedScript fscript(f.cx, f.script());
TypeScript::Monitor(f.cx, fscript, f.pc(), result);
}
/*
@ -1554,14 +1576,16 @@ stubs::StubTypeHelper(VMFrame &f, int32_t which)
void JS_FASTCALL
stubs::TypeBarrierReturn(VMFrame &f, Value *vp)
{
TypeScript::Monitor(f.cx, f.script(), f.pc(), vp[0]);
RootedScript fscript(f.cx, f.script());
TypeScript::Monitor(f.cx, fscript, f.pc(), vp[0]);
}
void JS_FASTCALL
stubs::NegZeroHelper(VMFrame &f)
{
f.regs.sp[-1].setDouble(-0.0);
TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
RootedScript fscript(f.cx, f.script());
TypeScript::MonitorOverflow(f.cx, fscript, f.pc());
}
void JS_FASTCALL
@ -1569,7 +1593,7 @@ stubs::CheckArgumentTypes(VMFrame &f)
{
StackFrame *fp = f.fp();
JSFunction *fun = fp->fun();
JSScript *script = fun->script();
RootedScript fscript(f.cx, fun->script());
RecompilationMonitor monitor(f.cx);
{
@ -1577,9 +1601,9 @@ stubs::CheckArgumentTypes(VMFrame &f)
types::AutoEnterTypeInference enter(f.cx);
if (!f.fp()->isConstructing())
TypeScript::SetThis(f.cx, script, fp->thisValue());
TypeScript::SetThis(f.cx, fscript, fp->thisValue());
for (unsigned i = 0; i < fun->nargs; i++)
TypeScript::SetArgument(f.cx, script, i, fp->unaliasedFormal(i, DONT_CHECK_ALIASING));
TypeScript::SetArgument(f.cx, fscript, i, fp->unaliasedFormal(i, DONT_CHECK_ALIASING));
}
if (monitor.recompiled())

View File

@ -147,7 +147,7 @@ JSC::MacroAssembler::Call
StubCompiler::emitStubCall(void *ptr, RejoinState rejoin, Uses uses, int32_t slots)
{
JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW CALL CODE ---- \n");
masm.bumpStubCount(cc.script, cc.PC, Registers::tempCallReg());
masm.bumpStubCount(cc.script_, cc.PC, Registers::tempCallReg());
DataLabelPtr inlinePatch;
Call cl = masm.fallibleVMCall(cx->typeInferenceEnabled(),
ptr, cc.outerPC(), &inlinePatch, slots);

View File

@ -46,20 +46,4 @@ try {
assertEq(actual, expect);
/* Make 64K blocks in a row, each with two vars, the second one named x. */
s = "{let y, x;}";
for (i = 0; i < 16; i++)
s += s;
/* Now append code to alias block 0 and botch a JS_NOT_REACHED or get the wrong x. */
s += "var g; { let x = 42; g = function() { return x; }; x = x; }";
try {
eval(s);
actual = g();
} catch (e) {
actual = e;
}
assertEq(actual, 42);
reportCompare(0, 0, "ok");

View File

@ -169,7 +169,7 @@ ArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, MutableHa
attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */
NormalArgumentsObject &argsobj = obj->asNormalArguments();
JSScript *script = argsobj.containingScript();
RootedScript script(cx, argsobj.containingScript());
if (JSID_IS_INT(id)) {
unsigned arg = unsigned(JSID_TO_INT(id));

View File

@ -1119,7 +1119,7 @@ class DebugScopeProxy : public BaseProxyHandler
/* Handle unaliased formals, vars, and consts at function scope. */
if (scope->isCall() && !scope->asCall().isForEval()) {
CallObject &callobj = scope->asCall();
JSScript *script = callobj.callee().script();
RootedScript script(cx, callobj.callee().script());
if (!script->ensureHasTypes(cx))
return false;

View File

@ -524,13 +524,13 @@ ContextStack::currentScript(jsbytecode **ppc,
if (!hasfp())
return NULL;
FrameRegs &regs = this->regs();
StackFrame *fp = regs.fp();
#ifdef JS_ION
if (fp->beginsIonActivation()) {
JSScript *script = NULL;
RootedScript script(cx_);
ion::GetPcScript(cx_, &script, ppc);
if (!allowCrossCompartment && script->compartment() != cx_->compartment)
return NULL;

View File

@ -43,10 +43,11 @@
*
* Extension:
*
* In addition, this header provides class |Scoped| and macro |SCOPED_TEMPLATE|
* to simplify the definition of RAII classes for other scenarios. These macros
* have been used to automatically close file descriptors/file handles when
* reaching the end of the scope, graphics contexts, etc.
* In addition, this header provides class |Scoped| and macros |SCOPED_TEMPLATE|
* and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE| to simplify the definition
* of RAII classes for other scenarios. These macros have been used to
* automatically close file descriptors/file handles when reaching the end of
* the scope, graphics contexts, etc.
*/
#include "mozilla/Attributes.h"
@ -223,6 +224,46 @@ struct ScopedDeleteArrayTraits : public ScopedFreePtrTraits<T>
};
SCOPED_TEMPLATE(ScopedDeleteArray, ScopedDeleteArrayTraits)
/*
* MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped
* pointers for types with custom deleters; just overload
* TypeSpecificDelete(T*) in the same namespace as T to call the deleter for
* type T.
*
* @param name The name of the class to define.
* @param Type A struct implementing clean-up. See the implementations
* for more details.
* *param Deleter The function that is used to delete/destroy/free a
* non-null value of Type*.
*
* Example:
*
* MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, \
* PR_Close)
* ...
* {
* ScopedPRFileDesc file(PR_OpenFile(...));
* ...
* } // file is closed with PR_Close here
*/
#define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \
inline void TypeSpecificDelete(Type * value) { Deleter(value); } \
typedef ::mozilla::TypeSpecificScopedPointer<Type> name;
template <typename T>
struct TypeSpecificScopedPointerTraits
{
typedef T* type;
const static type empty() { return NULL; }
const static void release(type value)
{
if (value)
TypeSpecificDelete(value);
}
};
SCOPED_TEMPLATE(TypeSpecificScopedPointer, TypeSpecificScopedPointerTraits)
} /* namespace mozilla */
#endif // mozilla_Scoped_h_

View File

@ -156,7 +156,7 @@ class GeckoInputConnection
@Override
public boolean finishComposingText() {
// finishComposingText() is called by the input method manager from the main
// finishComposingText() is called by the input method manager from a background
// thread so we have to make sure it's run in the ui thread.
postToUiThread(new Runnable() {
public void run() {
@ -304,6 +304,7 @@ class GeckoInputConnection
if (DEBUG) {
Log.d(LOGTAG, String.format("IME: replaceText(\"%s\", %d, %b)",
text, newCursorPosition, composing));
GeckoApp.assertOnUiThread();
}
if (text == null)
@ -427,8 +428,7 @@ class GeckoInputConnection
return InputMethods.getInputMethodManager(context);
}
protected void notifyTextChange(InputMethodManager imm, String text,
int start, int oldEnd, int newEnd) {
protected void notifyTextChange(String text, int start, int oldEnd, int newEnd) {
if (mBatchEditCount == 0) {
if (!text.contentEquals(mEditable)) {
if (DEBUG) Log.d(LOGTAG, ". . . notifyTextChange: current mEditable="
@ -443,13 +443,9 @@ class GeckoInputConnection
if (mUpdateRequest == null)
return;
View v = getView();
if (imm == null) {
imm = getInputMethodManager();
if (imm == null)
return;
}
InputMethodManager imm = getInputMethodManager();
if (imm == null)
return;
mUpdateExtract.flags = 0;
@ -468,10 +464,11 @@ class GeckoInputConnection
mUpdateExtract.text = updatedText;
mUpdateExtract.startOffset = 0;
View v = getView();
imm.updateExtractedText(v, mUpdateRequest.token, mUpdateExtract);
}
protected void notifySelectionChange(InputMethodManager imm, int start, int end) {
protected void notifySelectionChange(int start, int end) {
if (mBatchEditCount == 0) {
Span newSelection = Span.clamp(start, end, mEditable);
start = newSelection.start;
@ -503,16 +500,28 @@ class GeckoInputConnection
}
}
if (imm != null && imm.isFullscreenMode()) {
View v = getView();
if (hasCompositionString()) {
Span span = getComposingSpan();
imm.updateSelection(v, start, end, span.start, span.end);
} else {
imm.updateSelection(v, start, end, -1, -1);
// FIXME: Remove this postToUiThread() after bug 780543 is fixed.
final int oldStart = start;
final int oldEnd = end;
postToUiThread(new Runnable() {
public void run() {
InputMethodManager imm = getInputMethodManager();
if (imm != null && imm.isFullscreenMode()) {
int newStart;
int newEnd;
if (hasCompositionString()) {
Span span = getComposingSpan();
newStart = span.start;
newEnd = span.end;
} else {
newStart = -1;
newEnd = -1;
}
View v = getView();
imm.updateSelection(v, oldStart, oldEnd, newStart, newEnd);
}
}
}
});
}
protected void resetCompositionState() {
@ -691,11 +700,12 @@ class GeckoInputConnection
private void endComposition() {
if (DEBUG) {
Log.d(LOGTAG, "IME: endComposition: IME_COMPOSITION_END");
GeckoApp.assertOnUiThread();
}
if (!hasCompositionString())
Log.e(LOGTAG, "Please report this bug:",
new IllegalStateException("endComposition, but not composing text?!"));
Log.e(LOGTAG, "Please report this bug:",
new IllegalStateException("endComposition, but not composing text?!"));
GeckoAppShell.sendEventToGecko(
GeckoEvent.createIMEEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0));
@ -706,6 +716,7 @@ class GeckoInputConnection
private void sendTextToGecko(CharSequence text, int caretPos) {
if (DEBUG) {
Log.d(LOGTAG, "IME: sendTextToGecko(\"" + text + "\")");
GeckoApp.assertOnUiThread();
}
// Handle composition text styles
@ -1006,54 +1017,58 @@ class GeckoInputConnection
return mIMEState != IME_STATE_DISABLED;
}
public void notifyIME(int type, int state) {
View v = getView();
if (v == null)
return;
public void notifyIME(final int type, final int state) {
postToUiThread(new Runnable() {
public void run() {
View v = getView();
if (v == null)
return;
switch (type) {
case NOTIFY_IME_RESETINPUTSTATE:
if (DEBUG) Log.d(LOGTAG, ". . . notifyIME: reset");
switch (type) {
case NOTIFY_IME_RESETINPUTSTATE:
if (DEBUG) Log.d(LOGTAG, ". . . notifyIME: reset");
// Gecko just cancelled the current composition from underneath us,
// so abandon our active composition string WITHOUT committing it!
resetCompositionState();
// Gecko just cancelled the current composition from underneath us,
// so abandon our active composition string WITHOUT committing it!
resetCompositionState();
// Don't use IMEStateUpdater for reset.
// Because IME may not work showSoftInput()
// after calling restartInput() immediately.
// So we have to call showSoftInput() delay.
InputMethodManager imm = getInputMethodManager();
if (imm == null) {
// no way to reset IME status directly
IMEStateUpdater.resetIME();
} else {
imm.restartInput(v);
// Don't use IMEStateUpdater for reset.
// Because IME may not work showSoftInput()
// after calling restartInput() immediately.
// So we have to call showSoftInput() delay.
InputMethodManager imm = getInputMethodManager();
if (imm == null) {
// no way to reset IME status directly
IMEStateUpdater.resetIME();
} else {
imm.restartInput(v);
}
// keep current enabled state
IMEStateUpdater.enableIME();
break;
case NOTIFY_IME_CANCELCOMPOSITION:
if (DEBUG) Log.d(LOGTAG, ". . . notifyIME: cancel");
IMEStateUpdater.resetIME();
break;
case NOTIFY_IME_FOCUSCHANGE:
if (DEBUG) Log.d(LOGTAG, ". . . notifyIME: focus");
IMEStateUpdater.resetIME();
break;
case NOTIFY_IME_SETOPENSTATE:
default:
if (DEBUG)
throw new IllegalArgumentException("Unexpected NOTIFY_IME=" + type);
break;
}
}
// keep current enabled state
IMEStateUpdater.enableIME();
break;
case NOTIFY_IME_CANCELCOMPOSITION:
if (DEBUG) Log.d(LOGTAG, ". . . notifyIME: cancel");
IMEStateUpdater.resetIME();
break;
case NOTIFY_IME_FOCUSCHANGE:
if (DEBUG) Log.d(LOGTAG, ". . . notifyIME: focus");
IMEStateUpdater.resetIME();
break;
case NOTIFY_IME_SETOPENSTATE:
default:
if (DEBUG)
throw new IllegalArgumentException("Unexpected NOTIFY_IME=" + type);
break;
}
});
}
public void notifyIMEEnabled(int state, String typeHint, final String modeHint, String actionHint) {
public void notifyIMEEnabled(final int state, final String typeHint, final String modeHint, final String actionHint) {
// For some input type we will use a widget to display the ui, for those we must not
// display the ime. We can display a widget for date and time types and, if the sdk version
// is greater than 11, for datetime/month/week as well.
@ -1064,29 +1079,41 @@ class GeckoInputConnection
return;
}
View v = getView();
postToUiThread(new Runnable() {
public void run() {
View v = getView();
if (v == null)
return;
if (v == null)
return;
/* When IME is 'disabled', IME processing is disabled.
In addition, the IME UI is hidden */
mIMEState = state;
mIMETypeHint = (typeHint == null) ? "" : typeHint;
mIMEModeHint = (modeHint == null) ? "" : modeHint;
mIMEActionHint = (actionHint == null) ? "" : actionHint;
IMEStateUpdater.enableIME();
/* When IME is 'disabled', IME processing is disabled.
In addition, the IME UI is hidden */
mIMEState = state;
mIMETypeHint = (typeHint == null) ? "" : typeHint;
mIMEModeHint = (modeHint == null) ? "" : modeHint;
mIMEActionHint = (actionHint == null) ? "" : actionHint;
IMEStateUpdater.enableIME();
}
});
}
public void notifyIMEChange(String text, int start, int end, int newEnd) {
InputMethodManager imm = getInputMethodManager();
if (imm == null)
return;
if (newEnd < 0)
notifySelectionChange(imm, start, end);
else
notifyTextChange(imm, text, start, end, newEnd);
public final void notifyIMEChange(final String text, final int start, final int end,
final int newEnd) {
if (newEnd < 0) {
// FIXME: Post notifySelectionChange() to UI thread after bug 780543 is fixed.
// notifyIMEChange() is called on the Gecko thread. We want to run all
// InputMethodManager code on the UI thread to avoid IME race conditions that cause
// crashes like bug 747629. However, if notifySelectionChange() is run on the UI thread,
// it causes mysterious problems with repeating characters like bug 780543. This
// band-aid fix is to run all InputMethodManager code on the UI thread except
// notifySelectionChange() until I can find the root cause.
notifySelectionChange(start, end);
} else {
postToUiThread(new Runnable() {
public void run() {
notifyTextChange(text, start, end, newEnd);
}
});
}
}
/* Delay updating IME states (see bug 573800) */
@ -1117,25 +1144,30 @@ class GeckoInputConnection
instance = null;
}
final View v = getView();
if (v == null)
// TimerTask.run() is running on a random background thread, so post to UI thread.
postToUiThread(new Runnable() {
public void run() {
final View v = getView();
if (v == null)
return;
final InputMethodManager imm = getInputMethodManager();
if (imm == null)
return;
final InputMethodManager imm = getInputMethodManager();
if (imm == null)
return;
if (mReset)
imm.restartInput(v);
if (mReset)
imm.restartInput(v);
if (!mEnable)
return;
if (!mEnable)
return;
if (mIMEState != IME_STATE_DISABLED) {
imm.showSoftInput(v, 0);
} else if (imm.isActive(v)) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
if (mIMEState != IME_STATE_DISABLED) {
imm.showSoftInput(v, 0);
} else if (imm.isActive(v)) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
});
}
}
@ -1228,12 +1260,14 @@ class GeckoInputConnection
private static final class DebugGeckoInputConnection extends GeckoInputConnection {
public DebugGeckoInputConnection(View targetView) {
super(targetView);
GeckoApp.assertOnUiThread();
}
@Override
public boolean beginBatchEdit() {
Log.d(LOGTAG, "IME: beginBatchEdit: mBatchEditCount " + mBatchEditCount
+ " -> " + (mBatchEditCount+1));
GeckoApp.assertOnUiThread();
return super.beginBatchEdit();
}
@ -1241,6 +1275,7 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public boolean endBatchEdit() {
Log.d(LOGTAG, "IME: endBatchEdit: mBatchEditCount " + mBatchEditCount
+ " -> " + (mBatchEditCount-1));
GeckoApp.assertOnUiThread();
if (mBatchEditCount <= 0) {
throw new IllegalStateException("Expected positive mBatchEditCount, but got "
+ mBatchEditCount);
@ -1251,12 +1286,14 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
public boolean commitCompletion(CompletionInfo text) {
Log.d(LOGTAG, "IME: commitCompletion");
GeckoApp.assertOnUiThread();
return super.commitCompletion(text);
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
Log.d(LOGTAG, String.format("IME: commitText(\"%s\", %d)", text, newCursorPosition));
GeckoApp.assertOnUiThread();
return super.commitText(text, newCursorPosition);
}
@ -1264,6 +1301,7 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public boolean deleteSurroundingText(int leftLength, int rightLength) {
Log.d(LOGTAG, "IME: deleteSurroundingText(leftLen=" + leftLength + ", rightLen="
+ rightLength + ")");
GeckoApp.assertOnUiThread();
return super.deleteSurroundingText(leftLength, rightLength);
}
@ -1279,18 +1317,21 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public Editable getEditable() {
Editable editable = super.getEditable();
Log.d(LOGTAG, "IME: getEditable -> " + prettyPrintString(editable));
// FIXME: Uncomment assert after bug 780543 is fixed. //GeckoApp.assertOnUiThread();
return editable;
}
@Override
public boolean performContextMenuAction(int id) {
Log.d(LOGTAG, "IME: performContextMenuAction");
GeckoApp.assertOnUiThread();
return super.performContextMenuAction(id);
}
@Override
public ExtractedText getExtractedText(ExtractedTextRequest req, int flags) {
Log.d(LOGTAG, "IME: getExtractedText");
GeckoApp.assertOnUiThread();
ExtractedText extract = super.getExtractedText(req, flags);
if (extract != null)
Log.d(LOGTAG, String.format(
@ -1302,6 +1343,7 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
public CharSequence getTextAfterCursor(int length, int flags) {
Log.d(LOGTAG, "IME: getTextAfterCursor(length=" + length + ", flags=" + flags + ")");
GeckoApp.assertOnUiThread();
CharSequence s = super.getTextAfterCursor(length, flags);
Log.d(LOGTAG, ". . . getTextAfterCursor returns \"" + s + "\"");
return s;
@ -1310,6 +1352,7 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
public CharSequence getTextBeforeCursor(int length, int flags) {
Log.d(LOGTAG, "IME: getTextBeforeCursor");
GeckoApp.assertOnUiThread();
CharSequence s = super.getTextBeforeCursor(length, flags);
Log.d(LOGTAG, ". . . getTextBeforeCursor returns \"" + s + "\"");
return s;
@ -1318,24 +1361,28 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
Log.d(LOGTAG, String.format("IME: setComposingText(\"%s\", %d)", text, newCursorPosition));
GeckoApp.assertOnUiThread();
return super.setComposingText(text, newCursorPosition);
}
@Override
public boolean setComposingRegion(int start, int end) {
Log.d(LOGTAG, "IME: setComposingRegion(start=" + start + ", end=" + end + ")");
GeckoApp.assertOnUiThread();
return super.setComposingRegion(start, end);
}
@Override
public boolean setSelection(int start, int end) {
Log.d(LOGTAG, "IME: setSelection(start=" + start + ", end=" + end + ")");
GeckoApp.assertOnUiThread();
return super.setSelection(start, end);
}
@Override
public String getComposingText() {
Log.d(LOGTAG, "IME: getComposingText");
GeckoApp.assertOnUiThread();
String s = super.getComposingText();
Log.d(LOGTAG, ". . . getComposingText: Composing text = \"" + s + "\"");
return s;
@ -1344,30 +1391,36 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
public boolean onKeyDel() {
Log.d(LOGTAG, "IME: onKeyDel");
GeckoApp.assertOnUiThread();
return super.onKeyDel();
}
@Override
protected void notifyTextChange(InputMethodManager imm, String text,
int start, int oldEnd, int newEnd) {
protected void notifyTextChange(String text, int start, int oldEnd, int newEnd) {
// notifyTextChange() call is posted to UI thread from notifyIMEChange().
GeckoApp.assertOnUiThread();
String msg = String.format("IME: >notifyTextChange(%s, start=%d, oldEnd=%d, newEnd=%d)",
prettyPrintString(text), start, oldEnd, newEnd);
Log.d(LOGTAG, msg);
if (start < 0 || oldEnd < start || newEnd < start || newEnd > text.length()) {
throw new IllegalArgumentException("BUG! " + msg);
}
super.notifyTextChange(imm, text, start, oldEnd, newEnd);
super.notifyTextChange(text, start, oldEnd, newEnd);
}
@Override
protected void notifySelectionChange(InputMethodManager imm, int start, int end) {
protected void notifySelectionChange(int start, int end) {
// notifySelectionChange() call is posted to UI thread from notifyIMEChange().
// FIXME: Uncomment assert after bug 780543 is fixed.
//GeckoApp.assertOnUiThread();
Log.d(LOGTAG, String.format("IME: >notifySelectionChange(start=%d, end=%d)", start, end));
super.notifySelectionChange(imm, start, end);
super.notifySelectionChange(start, end);
}
@Override
protected void resetCompositionState() {
Log.d(LOGTAG, "IME: resetCompositionState");
GeckoApp.assertOnUiThread();
if (hasCompositionString()) {
Log.d(LOGTAG, "resetCompositionState() is abandoning an active composition string");
}
@ -1378,12 +1431,14 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d(LOGTAG, String.format("IME: onTextChanged(\"%s\" start=%d, before=%d, count=%d)",
s, start, before, count));
GeckoApp.assertOnUiThread();
super.onTextChanged(s, start, before, count);
}
@Override
public void afterTextChanged(Editable s) {
Log.d(LOGTAG, "IME: afterTextChanged(\"" + s + "\")");
GeckoApp.assertOnUiThread();
super.afterTextChanged(s);
}
@ -1391,30 +1446,35 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.d(LOGTAG, String.format("IME: beforeTextChanged(\"%s\", start=%d, count=%d, after=%d)",
s, start, count, after));
GeckoApp.assertOnUiThread();
super.beforeTextChanged(s, start, count, after);
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
Log.d(LOGTAG, "IME: onCreateInputConnection called");
GeckoApp.assertOnUiThread();
return super.onCreateInputConnection(outAttrs);
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyPreIme(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyPreIme(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyDown(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyUp(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyUp(keyCode, event);
}
@ -1422,18 +1482,21 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyMultiple(keyCode=" + keyCode + ", repeatCount=" + repeatCount
+ ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyMultiple(keyCode, repeatCount, event);
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyLongPress(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyLongPress(keyCode, event);
}
@Override
public void notifyIME(int type, int state) {
Log.d(LOGTAG, "IME: >notifyIME(type=" + type + ", state=" + state + ")");
GeckoApp.assertOnGeckoThread();
super.notifyIME(type, state);
}
@ -1442,6 +1505,7 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
Log.d(LOGTAG, "IME: >notifyIMEEnabled(state=" + state + ", typeHint=\"" + typeHint
+ "\", modeHint=\"" + modeHint + "\", actionHint=\""
+ actionHint + "\"");
GeckoApp.assertOnGeckoThread();
if (state < IME_STATE_DISABLED || state > IME_STATE_PLUGIN)
throw new IllegalArgumentException("Unexpected IMEState=" + state);
super.notifyIMEEnabled(state, typeHint, modeHint, actionHint);

View File

@ -35,7 +35,7 @@ XPCOMUtils.defineLazyGetter(window, "gChromeWin", function ()
.QueryInterface(Ci.nsIDOMChromeWindow));
let Downloads = {
init: function () {
init: function dl_init() {
this._list = document.getElementById("downloads-list");
this._list.addEventListener("click", function (event) {
let target = event.target;
@ -113,7 +113,7 @@ let Downloads = {
);
},
uninit: function () {
uninit: function dl_uninit() {
let contextmenus = gChromeWin.NativeWindow.contextmenus;
contextmenus.remove(this.openMenuItem);
contextmenus.remove(this.removeMenuItem);
@ -131,7 +131,7 @@ let Downloads = {
Services.obs.removeObserver(this, "dl-cancel");
},
observe: function (aSubject, aTopic, aData) {
observe: function dl_observe(aSubject, aTopic, aData) {
let download = aSubject.QueryInterface(Ci.nsIDownload);
switch (aTopic) {
case "dl-blocked":
@ -154,7 +154,7 @@ let Downloads = {
}
},
_moveDownloadAfterActive: function (aItem) {
_moveDownloadAfterActive: function dl_moveDownloadAfterActive(aItem) {
// Move downloads that just reached a "completed" state below any active
try {
// Iterate down until we find a non-active download
@ -168,7 +168,7 @@ let Downloads = {
}
},
_inProgress: function (aState) {
_inProgress: function dl_inProgress(aState) {
return [
this._dlmgr.DOWNLOAD_NOTSTARTED,
this._dlmgr.DOWNLOAD_QUEUED,
@ -178,7 +178,7 @@ let Downloads = {
].indexOf(parseInt(aState)) != -1;
},
_insertDownloadRow: function (aDownload) {
_insertDownloadRow: function dl_insertDownloadRow(aDownload) {
let updatedState = this._getState(aDownload.state);
let item = this._createItem(downloadTemplate, {
id: aDownload.id,
@ -193,7 +193,7 @@ let Downloads = {
this._list.insertAdjacentHTML("afterbegin", item);
},
_getDownloadSize: function (aSize) {
_getDownloadSize: function dl_getDownloadSize(aSize) {
let displaySize = DownloadUtils.convertByteUnits(aSize);
if (displaySize[0] > 0) // [0] is size, [1] is units
return displaySize.join("");
@ -202,7 +202,7 @@ let Downloads = {
},
// Not all states are displayed as-is on mobile, some are translated to a generic state
_getState: function (aState) {
_getState: function dl_getState(aState) {
let str;
switch (aState) {
// Downloading and Scanning states show up as "Downloading"
@ -230,7 +230,7 @@ let Downloads = {
},
// Note: This doesn't cover all states as some of the states are translated in _getState()
_getStateString: function (aState) {
_getStateString: function dl_getStateString(aState) {
let str;
switch (aState) {
case this._dlmgr.DOWNLOAD_DOWNLOADING:
@ -258,7 +258,7 @@ let Downloads = {
return gStrings.GetStringFromName(str);
},
_updateItem: function (aItem, aValues) {
_updateItem: function dl_updateItem(aItem, aValues) {
for (let i in aValues) {
aItem.querySelector("." + i).textContent = aValues[i];
}
@ -338,7 +338,7 @@ let Downloads = {
}
},
getDownloads: function () {
getDownloads: function dl_getDownloads() {
this._dlmgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
this._initStatement();
@ -359,16 +359,16 @@ let Downloads = {
}, 0);
},
_getElementForDownload: function (aKey) {
_getElementForDownload: function dl_getElementForDownload(aKey) {
return this._list.querySelector("li[downloadID='" + aKey + "']");
},
_getDownloadForElement: function (aElement) {
_getDownloadForElement: function dl_getDownloadForElement(aElement) {
let id = parseInt(aElement.getAttribute("downloadID"));
return this._dlmgr.getDownload(id);
},
_removeItem: function dv__removeItem(aItem) {
_removeItem: function dl_removeItem(aItem) {
// Make sure we have an item to remove
if (!aItem)
return;
@ -378,7 +378,7 @@ let Downloads = {
this._list.selectedIndex = Math.min(index, this._list.itemCount - 1);
},
openDownload: function (aItem) {
openDownload: function dl_openDownload(aItem) {
let f = null;
try {
let download = this._getDownloadForElement(aItem);
@ -390,7 +390,7 @@ let Downloads = {
} catch (ex) { }
},
removeDownload: function (aItem) {
removeDownload: function dl_removeDownload(aItem) {
let f = null;
try {
let download = this._getDownloadForElement(aItem);
@ -410,7 +410,7 @@ let Downloads = {
} catch(ex) { }
},
pauseDownload: function (aItem) {
pauseDownload: function dl_pauseDownload(aItem) {
try {
let download = this._getDownloadForElement(aItem);
this._dlmgr.pauseDownload(aItem.getAttribute("downloadID"));
@ -421,7 +421,7 @@ let Downloads = {
},
resumeDownload: function (aItem) {
resumeDownload: function dl_resumeDownload(aItem) {
try {
let download = this._getDownloadForElement(aItem);
this._dlmgr.resumeDownload(aItem.getAttribute("downloadID"));
@ -431,7 +431,7 @@ let Downloads = {
}
},
retryDownload: function (aItem) {
retryDownload: function dl_retryDownload(aItem) {
try {
let download = this._getDownloadForElement(aItem);
this._removeItem(aItem);
@ -441,7 +441,7 @@ let Downloads = {
}
},
cancelDownload: function (aItem) {
cancelDownload: function dl_cancelDownload(aItem) {
try {
this._dlmgr.cancelDownload(aItem.getAttribute("downloadID"));
let download = this._getDownloadForElement(aItem);
@ -456,7 +456,7 @@ let Downloads = {
}
},
_updateDownloadRow: function (aItem){
_updateDownloadRow: function dl_updateDownloadRow(aItem){
try {
let download = this._getDownloadForElement(aItem);
let updatedState = this._getState(download.state);

View File

@ -582,6 +582,173 @@ File.Info.fromMsg = function fromMsg(value) {
return new File.Info(value);
};
/**
* Iterate asynchronously through a directory
*
* @constructor
*/
let DirectoryIterator = function DirectoryIterator(path, options) {
/**
* Open the iterator on the worker thread
*
* @type {Promise}
* @resolves {*} A message accepted by the methods of DirectoryIterator
* in the worker thread
* @rejects {StopIteration} If all entries have already been visited
* or the iterator has been closed.
*/
this._itmsg = Scheduler.post(
"new_DirectoryIterator", [Type.path.toMsg(path), options],
path
);
this._isClosed = false;
};
DirectoryIterator.prototype = {
/**
* Get the next entry in the directory.
*
* @return {Promise}
* @resolves {OS.File.Entry}
* @rejects {StopIteration} If all entries have already been visited.
*/
next: function next() {
let self = this;
let promise = this._itmsg;
// Get the iterator, call _next
promise = promise.then(
function withIterator(iterator) {
return self._next(iterator);
});
return promise;
},
/**
* Get several entries at once.
*
* @param {number=} length If specified, the number of entries
* to return. If unspecified, return all remaining entries.
* @return {Promise}
* @resolves {Array} An array containing the |length| next entries.
*/
nextBatch: function nextBatch(size) {
if (this._isClosed) {
return Promise.resolve([]);
}
let promise = this._itmsg;
promise = promise.then(
function withIterator(iterator) {
return Scheduler.post("DirectoryIterator_prototype_nextBatch", [iterator, size]);
});
promise = promise.then(
function withEntries(array) {
return array.map(DirectoryIterator.Entry.fromMsg);
});
return promise;
},
/**
* Apply a function to all elements of the directory sequentially.
*
* @param {Function} cb This function will be applied to all entries
* of the directory. It receives as arguments
* - the OS.File.Entry corresponding to the entry;
* - the index of the entry in the enumeration;
* - the iterator itself - return |iterator.close()| to stop the loop.
*
* If the callback returns a promise, iteration waits until the
* promise is resolved before proceeding.
*
* @return {Promise} A promise resolved once the loop has reached
* its end.
*/
forEach: function forEach(cb, options) {
if (this._isClosed) {
return Promise.resolve();
}
let self = this;
let position = 0;
let iterator;
// Grab iterator
let promise = this._itmsg.then(
function(aIterator) {
iterator = aIterator;
}
);
// Then iterate
let loop = function loop() {
if (self._isClosed) {
return Promise.resolve();
}
return self._next(iterator).then(
function onSuccess(value) {
return Promise.resolve(cb(value, position++, self)).then(loop);
},
function onFailure(reason) {
if (reason == StopIteration) {
return;
}
throw reason;
}
);
};
return promise.then(loop);
},
/**
* Auxiliary method: fetch the next item
*
* @rejects {StopIteration} If all entries have already been visited
* or the iterator has been closed.
*/
_next: function _next(iterator) {
if (this._isClosed) {
LOG("DirectoryIterator._next", "closed");
return this._itmsg;
}
let self = this;
let promise = Scheduler.post("DirectoryIterator_prototype_next", [iterator]);
promise = promise.then(
DirectoryIterator.Entry.fromMsg,
function onReject(reason) {
// If the exception is |StopIteration| (which we may determine only
// from its message...) we need to stop the iteration.
if (!(reason instanceof WorkerErrorEvent && reason.message == "uncaught exception: [object StopIteration]")) {
// Any exception other than StopIteration should be propagated as such
throw reason;
}
self.close();
throw StopIteration;
});
return promise;
},
/**
* Close the iterator
*/
close: function close() {
if (this._isClosed) {
return;
}
this._isClosed = true;
let self = this;
this._itmsg.then(
function withIterator(iterator) {
self._itmsg = Promise.reject(StopIteration);
return Scheduler.post("DirectoryIterator_prototype_close", [iterator]);
}
);
}
};
DirectoryIterator.Entry = function Entry(value) {
return value;
};
DirectoryIterator.Entry.fromMsg = function fromMsg(value) {
return new DirectoryIterator.Entry(value);
};
// Constants
Object.defineProperty(File, "POS_START", {value: OS.Shared.POS_START});
Object.defineProperty(File, "POS_CURRENT", {value: OS.Shared.POS_CURRENT});
@ -589,4 +756,4 @@ Object.defineProperty(File, "POS_END", {value: OS.Shared.POS_END});
OS.File = File;
OS.File.Error = OSError;
OS.File.DirectoryIterator = DirectoryIterator;

View File

@ -151,6 +151,18 @@ if (this.Components) {
return f.call(file);
};
let OpenedDirectoryIterators = new ResourceTracker();
let withDir = function withDir(fd, f) {
let file = OpenedDirectoryIterators.get(fd);
if (file == null) {
throw new Error("Could not find Directory");
}
if (!(file instanceof File.DirectoryIterator)) {
throw new Error("file is not a directory iterator " + file.__proto__.toSource());
}
return f.call(file);
};
let Type = exports.OS.Shared.Type;
let File = exports.OS.File;
@ -192,6 +204,10 @@ if (this.Components) {
let file = File.open(Type.path.fromMsg(path), mode, options);
return OpenedFiles.add(file);
},
new_DirectoryIterator: function new_DirectoryIterator(path, options) {
let iterator = new File.DirectoryIterator(Type.path.fromMsg(path), options);
return OpenedDirectoryIterators.add(iterator);
},
// Methods of OS.File
File_prototype_close: function close(fd) {
return withFile(fd,
@ -227,19 +243,51 @@ if (this.Components) {
return withFile(fd,
function do_setPosition() {
return this.setPosition(pos, whence);
}
);
});
},
File_prototype_getPosition: function getPosition(fd) {
return withFile(fd,
function do_getPosition() {
return this.getPosition();
}
);
});
},
// Methods of OS.File.DirectoryIterator
DirectoryIterator_prototype_next: function next(dir) {
return withDir(dir,
function do_next() {
try {
return File.DirectoryIterator.Entry.toMsg(this.next());
} catch (x) {
if (x == StopIteration) {
OpenedDirectoryIterators.remove(dir);
}
throw x;
}
});
},
DirectoryIterator_prototype_nextBatch: function nextBatch(dir, size) {
return withDir(dir,
function do_nextBatch() {
let result;
try {
result = this.nextBatch(size);
} catch (x) {
OpenedDirectoryIterators.remove(dir);
throw x;
}
return result.map(File.DirectoryIterator.Entry.toMsg);
});
},
DirectoryIterator_prototype_close: function close(dir) {
return withDir(dir,
function do_close() {
this.close();
OpenedDirectoryIterators.remove(dir);
});
}
};
} catch(ex) {
dump("WORKER ERROR DURING SETUP " + ex + "\n");
dump("WORKER ERROR DETAIL " + ex.stack);
dump("WORKER ERROR DETAIL " + ex.stack + "\n");
}
})(this);

View File

@ -515,7 +515,7 @@
if (options.noOverwrite) {
dest = File.open(destPath, {create:true});
} else {
dest = File.open(destPath, {write:true});
dest = File.open(destPath, {trunc:true});
}
result = pump(source, dest, options);
} catch (x) {

View File

@ -159,7 +159,8 @@ let test = maketest("Main",
function main(test) {
SimpleTest.waitForExplicitFinish();
let tests = [test_constants, test_path, test_open, test_stat,
test_read_write, test_position, test_copy];
test_read_write, test_position, test_copy,
test_iter];
let current = 0;
let aux = function aux() {
if (current >= tests.length) {
@ -673,4 +674,137 @@ let test_mkdir = maketest("mkdir",
);
return promise;
});
});
let test_iter = maketest("iter",
function iter(test) {
let path;
let promise = OS.File.getCurrentDirectory();
let temporary_file_name;
let iterator;
// Trivial walks through the directory
promise = promise.then(
function obtained_current_directory(aPath) {
test.info("Preparing iteration");
path = aPath;
iterator = new OS.File.DirectoryIterator(aPath);
temporary_file_name = OS.Path.join(path, "empty-temporary-file.tmp");
return OS.File.remove(temporary_file_name);
}
);
// Ignore errors removing file
promise = promise.then(null, function() {});
promise = promise.then(
function removed_temporary_file() {
return iterator.nextBatch();
}
);
let allfiles1;
promise = promise.then(
function obtained_allfiles1(aAllFiles) {
test.info("Obtained all files through nextBatch");
allfiles1 = aAllFiles;
test.isnot(allfiles1.length, 0, "There is at least one file");
test.isnot(allfiles1[0].path, null, "Files have a path");
return iterator.close();
});
let allfiles2 = [];
let i = 0;
promise = promise.then(
function closed_iterator() {
test.info("Closed iterator");
iterator = new OS.File.DirectoryIterator(path);
return iterator.forEach(function(entry, index) {
is(i++, index, "Getting the correct index");
allfiles2.push(entry);
});
}
);
promise = promise.then(
function obtained_allfiles2() {
test.info("Obtained all files through forEach");
is(allfiles1.length, allfiles2.length, "Both runs returned the same number of files");
for (let i = 0; i < allfiles1.length; ++i) {
if (allfiles1[i].path != allfiles2[i].path) {
test.is(allfiles1[i].path, allfiles2[i].path, "Both runs return the same files");
break;
}
}
}
);
// Testing batch iteration + whether an iteration can be stopped early
let BATCH_LENGTH = 10;
promise = promise.then(
function compared_allfiles() {
test.info("Getting some files through nextBatch");
iterator.close();
iterator = new OS.File.DirectoryIterator(path);
return iterator.nextBatch(BATCH_LENGTH);
}
);
let somefiles1;
promise = promise.then(
function obtained_somefiles1(aFiles) {
somefiles1 = aFiles;
return iterator.nextBatch(BATCH_LENGTH);
}
);
let somefiles2;
promise = promise.then(
function obtained_somefiles2(aFiles) {
somefiles2 = aFiles;
iterator.close();
iterator = new OS.File.DirectoryIterator(path);
return iterator.forEach(
function cb(entry, index, iterator) {
if (index < BATCH_LENGTH) {
test.is(entry.path, somefiles1[index].path, "Both runs return the same files (part 1)");
} else if (index < 2*BATCH_LENGTH) {
test.is(entry.path, somefiles2[index - BATCH_LENGTH].path, "Both runs return the same files (part 2)");
} else if (index == 2 * BATCH_LENGTH) {
test.info("Attempting to stop asynchronous forEach");
return iterator.close();
} else {
test.fail("Can we stop an asynchronous forEach? " + index);
}
return null;
});
}
);
// Ensuring that we find new files if they appear
promise = promise.then(
function create_temporary_file() {
return OS.File.open(temporary_file_name, { write: true } );
}
);
promise = promise.then(
function with_temporary_file(file) {
file.close();
iterator = new OS.File.DirectoryIterator(path);
return iterator.nextBatch();
}
);
promise = promise.then(
function with_new_list(aFiles) {
is(aFiles.length, allfiles1.length + 1, "The directory iterator has noticed the new file");
}
);
promise = always(promise,
function cleanup() {
if (iterator) {
iterator.close();
}
}
);
return promise;
});

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