mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-28 13:21:28 +00:00
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
commit
b7e92a6866
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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">
|
||||
|
@ -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)
|
||||
|
@ -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">
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 */
|
@ -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
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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 = {
|
||||
|
@ -16,6 +16,7 @@ GRE_MODULE = 1
|
||||
|
||||
XPIDLSRCS = \
|
||||
mozIApplication.idl \
|
||||
mozIApplicationClearPrivateDataParams.idl \
|
||||
nsIDOMApplicationRegistry.idl \
|
||||
nsIDOMApplicationRegistry2.idl \
|
||||
nsIAppsService.idl \
|
||||
|
@ -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;
|
||||
};
|
@ -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)]
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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)",
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -36,6 +36,7 @@ for (var p in props) {
|
||||
|
||||
var mgmtProps = {
|
||||
QueryInterface: "function",
|
||||
applyDownload: "function",
|
||||
getAll: "function",
|
||||
getNotInstalled: "function",
|
||||
oninstall: "object",
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "ion/IonMacroAssembler.h"
|
||||
#include "gc/Marking.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::ion;
|
||||
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include "MoveEmitter-x86-shared.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::ion;
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "Assembler-x64.h"
|
||||
#include "gc/Marking.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::ion;
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "ion/MoveEmitter.h"
|
||||
#include "ion/IonFrames.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::ion;
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "ion/VMFunctions.h"
|
||||
#include "ion/IonSpewer.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::ion;
|
||||
|
||||
|
8
js/src/jit-test/tests/ion/bug792166-1.js
Normal file
8
js/src/jit-test/tests/ion/bug792166-1.js
Normal 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;
|
||||
}
|
8
js/src/jit-test/tests/ion/bug792166-2.js
Normal file
8
js/src/jit-test/tests/ion/bug792166-2.js
Normal file
@ -0,0 +1,8 @@
|
||||
try {
|
||||
__defineGetter__("eval", function() {
|
||||
this["__proto__"]
|
||||
})
|
||||
delete this["__proto__"]
|
||||
this["__proto__"]
|
||||
} catch (e) {}
|
||||
eval
|
@ -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 */
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
@ -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. */
|
||||
|
@ -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);
|
||||
|
@ -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 ®s)
|
||||
TypeCheckNextBytecode(JSContext *cx, JSScript *script_, unsigned n, const FrameRegs ®s)
|
||||
{
|
||||
#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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -240,6 +240,7 @@ enum ThingRootKind
|
||||
THING_ROOT_PROPERTY_ID,
|
||||
THING_ROOT_VALUE,
|
||||
THING_ROOT_TYPE,
|
||||
THING_ROOT_BINDINGS,
|
||||
THING_ROOT_LIMIT
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -406,7 +406,7 @@ private:
|
||||
ActiveFrame *a;
|
||||
ActiveFrame *outer;
|
||||
|
||||
JSScript *script;
|
||||
JSScript *script_;
|
||||
analyze::ScriptAnalysis *analysis;
|
||||
jsbytecode *PC;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -524,13 +524,13 @@ ContextStack::currentScript(jsbytecode **ppc,
|
||||
|
||||
if (!hasfp())
|
||||
return NULL;
|
||||
|
||||
|
||||
FrameRegs ®s = 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;
|
||||
|
@ -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_
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
@ -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) {
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user