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

This commit is contained in:
Ed Morley 2012-05-17 10:59:25 +01:00
commit 50c4cb2d1d
102 changed files with 9296 additions and 6981 deletions

View File

@ -8868,7 +8868,8 @@ let gPrivateBrowsingUI = {
* and the setter should only be used in tests.
*/
get privateWindow() {
return window.getInterface(Ci.nsIWebNavigation)
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
@ -8878,7 +8879,8 @@ let gPrivateBrowsingUI = {
},
set privateWindow(val) {
return window.getInterface(Ci.nsIWebNavigation)
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)

View File

@ -65,7 +65,7 @@ let gSyncPane = {
this.needsUpdate();
} else {
this.page = PAGE_HAS_ACCOUNT;
document.getElementById("accountName").value = Weave.Service.account;
document.getElementById("accountName").value = Weave.Identity.account;
document.getElementById("syncComputerName").value = Weave.Clients.localName;
document.getElementById("tosPP").hidden = this._usingCustomServer;
}

View File

@ -95,6 +95,7 @@ function PrivateBrowsingService() {
this._obs.addObserver(this, "private-browsing", true);
this._obs.addObserver(this, "command-line-startup", true);
this._obs.addObserver(this, "sessionstore-browser-state-restored", true);
this._obs.addObserver(this, "domwindowopened", true);
// List of nsIXULWindows we are going to be closing during the transition
this._windowsToClose = [];
@ -152,6 +153,17 @@ PrivateBrowsingService.prototype = {
this.privateBrowsingEnabled = false;
},
_setPerWindowPBFlag: function PBS__setPerWindowPBFlag(aWindow, aFlag) {
aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIXULWindow)
.docShell.QueryInterface(Ci.nsILoadContext)
.usePrivateBrowsing = aFlag;
},
_onBeforePrivateBrowsingModeChange: function PBS__onBeforePrivateBrowsingModeChange() {
// nothing needs to be done here if we're enabling at startup
if (!this._autoStarted) {
@ -222,23 +234,15 @@ PrivateBrowsingService.prototype = {
.docShell.contentViewer.resetCloseWindow();
}
}
if (!this._quitting) {
var windowsEnum = Services.wm.getEnumerator("navigator:browser");
while (windowsEnum.hasMoreElements()) {
var window = windowsEnum.getNext();
window.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIXULWindow)
.docShell.QueryInterface(Ci.nsILoadContext)
.usePrivateBrowsing = this._inPrivateBrowsing;
}
}
}
else
this._saveSession = false;
var windowsEnum = Services.wm.getEnumerator("navigator:browser");
while (windowsEnum.hasMoreElements()) {
var window = windowsEnum.getNext();
this._setPerWindowPBFlag(window, this._inPrivateBrowsing);
}
},
_onAfterPrivateBrowsingModeChange: function PBS__onAfterPrivateBrowsingModeChange() {
@ -523,6 +527,18 @@ PrivateBrowsingService.prototype = {
this._notifyIfTransitionComplete();
}
break;
case "domwindowopened":
let aWindow = aSubject;
let self = this;
aWindow.addEventListener("load", function PBS__onWindowLoad(aEvent) {
aWindow.removeEventListener("load", arguments.callee);
if (aWindow.document
.documentElement
.getAttribute("windowtype") == "navigator:browser") {
self._setPerWindowPBFlag(aWindow, self._inPrivateBrowsing);
}
}, false);
break;
}
},

View File

@ -40,6 +40,7 @@
function test() {
// initialization
waitForExplicitFinish();
gPrefService.setBoolPref("browser.privatebrowsing.keep_current_session", true);
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
@ -54,6 +55,27 @@ function test() {
gBrowser.selectedTab = gBrowser.addTab();
let originalTitle = document.title;
function testNewWindow(aCallback, expected) {
Services.obs.addObserver(function observer1(aSubject, aTopic, aData) {
aSubject.addEventListener("load", function() {
aSubject.removeEventListener("load", arguments.callee);
executeSoon(function() {
let ui = aSubject.gPrivateBrowsingUI;
is(ui.privateBrowsingEnabled, expected, "The privateBrowsingEnabled property on the new window is set correctly");
is(ui.privateWindow, expected, "The privateWindow property on the new window is set correctly");
Services.obs.addObserver(function observer2(aSubject, aTopic, aData) {
aCallback();
Services.obs.removeObserver(observer2, "domwindowclosed");
}, "domwindowclosed", false);
aSubject.close();
});
Services.obs.removeObserver(observer1, "domwindowopened");
}, false);
}, "domwindowopened", false);
OpenBrowserWindow();
}
// test the gPrivateBrowsingUI object
ok(gPrivateBrowsingUI, "The gPrivateBrowsingUI object exists");
is(pb.privateBrowsingEnabled, false, "The private browsing mode should not be started initially");
@ -61,45 +83,53 @@ function test() {
is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
ok(pbMenuItem, "The Private Browsing menu item exists");
is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("startlabel"), "The Private Browsing menu item should read \"Start Private Browsing\"");
gPrivateBrowsingUI.toggleMode();
is(pb.privateBrowsingEnabled, true, "The private browsing mode should be started");
is(gPrivateBrowsingUI.privateBrowsingEnabled, true, "gPrivateBrowsingUI should expose the correct private browsing status");
is(gPrivateBrowsingUI.privateWindow, true, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
// check to see if the Private Browsing mode was activated successfully
is(observerData, "enter", "Private Browsing mode was activated using the gPrivateBrowsingUI object");
is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("stoplabel"), "The Private Browsing menu item should read \"Stop Private Browsing\"");
gPrivateBrowsingUI.toggleMode()
is(pb.privateBrowsingEnabled, false, "The private browsing mode should not be started");
is(gPrivateBrowsingUI.privateBrowsingEnabled, false, "gPrivateBrowsingUI should expose the correct private browsing status");
is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
// check to see if the Private Browsing mode was deactivated successfully
is(observerData, "exit", "Private Browsing mode was deactivated using the gPrivateBrowsingUI object");
is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("startlabel"), "The Private Browsing menu item should read \"Start Private Browsing\"");
testNewWindow(function() {
gPrivateBrowsingUI.toggleMode();
is(pb.privateBrowsingEnabled, true, "The private browsing mode should be started");
is(gPrivateBrowsingUI.privateBrowsingEnabled, true, "gPrivateBrowsingUI should expose the correct private browsing status");
is(gPrivateBrowsingUI.privateWindow, true, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
// check to see if the Private Browsing mode was activated successfully
is(observerData, "enter", "Private Browsing mode was activated using the gPrivateBrowsingUI object");
is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("stoplabel"), "The Private Browsing menu item should read \"Stop Private Browsing\"");
testNewWindow(function() {
gPrivateBrowsingUI.toggleMode()
is(pb.privateBrowsingEnabled, false, "The private browsing mode should not be started");
is(gPrivateBrowsingUI.privateBrowsingEnabled, false, "gPrivateBrowsingUI should expose the correct private browsing status");
is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
// check to see if the Private Browsing mode was deactivated successfully
is(observerData, "exit", "Private Browsing mode was deactivated using the gPrivateBrowsingUI object");
is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("startlabel"), "The Private Browsing menu item should read \"Start Private Browsing\"");
// These are tests for the privateWindow setter. Note that the setter should
// not be used anywhere else for now!
gPrivateBrowsingUI.privateWindow = true;
is(gPrivateBrowsingUI.privateWindow, true, "gPrivateBrowsingUI should accept the correct per-window private browsing status");
gPrivateBrowsingUI.privateWindow = false;
is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should accept the correct per-window private browsing status");
testNewWindow(function() {
// These are tests for the privateWindow setter. Note that the setter should
// not be used anywhere else for now!
gPrivateBrowsingUI.privateWindow = true;
is(gPrivateBrowsingUI.privateWindow, true, "gPrivateBrowsingUI should accept the correct per-window private browsing status");
gPrivateBrowsingUI.privateWindow = false;
is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should accept the correct per-window private browsing status");
// now, test using the <command> object
let cmd = document.getElementById("Tools:PrivateBrowsing");
isnot(cmd, null, "XUL command object for the private browsing service exists");
var func = new Function("", cmd.getAttribute("oncommand"));
func.call(cmd);
// check to see if the Private Browsing mode was activated successfully
is(observerData, "enter", "Private Browsing mode was activated using the command object");
// check to see that the window title has been changed correctly
isnot(document.title, originalTitle, "Private browsing mode has correctly changed the title");
func.call(cmd);
// check to see if the Private Browsing mode was deactivated successfully
is(observerData, "exit", "Private Browsing mode was deactivated using the command object");
// check to see that the window title has been restored correctly
is(document.title, originalTitle, "Private browsing mode has correctly restored the title");
// now, test using the <command> object
let cmd = document.getElementById("Tools:PrivateBrowsing");
isnot(cmd, null, "XUL command object for the private browsing service exists");
var func = new Function("", cmd.getAttribute("oncommand"));
func.call(cmd);
// check to see if the Private Browsing mode was activated successfully
is(observerData, "enter", "Private Browsing mode was activated using the command object");
// check to see that the window title has been changed correctly
isnot(document.title, originalTitle, "Private browsing mode has correctly changed the title");
func.call(cmd);
// check to see if the Private Browsing mode was deactivated successfully
is(observerData, "exit", "Private Browsing mode was deactivated using the command object");
// check to see that the window title has been restored correctly
is(document.title, originalTitle, "Private browsing mode has correctly restored the title");
// cleanup
gBrowser.removeCurrentTab();
Services.obs.removeObserver(observer, "private-browsing");
gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
// cleanup
gBrowser.removeCurrentTab();
Services.obs.removeObserver(observer, "private-browsing");
gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
finish();
}, false);
}, true);
}, false);
}

View File

@ -1716,6 +1716,7 @@ GK_ATOM(onMozTouchUp, "onMozTouchUp")
GK_ATOM(ondevicemotion, "ondevicemotion")
GK_ATOM(ondeviceorientation, "ondeviceorientation")
GK_ATOM(ondeviceproximity, "ondeviceproximity")
GK_ATOM(onuserproximity, "onuserproximity")
// light sensor support
GK_ATOM(ondevicelight, "ondevicelight")

View File

@ -390,10 +390,14 @@ nsWebSocket::OnServerClose(nsISupports *aContext, PRUint16 aCode,
CopyUTF8toUTF16(aReason, mCloseEventReason);
if (mReadyState == nsIWebSocket::OPEN) {
// Send reciprocal Close frame.
// 5.5.1: "When sending a Close frame in response, the endpoint typically
// echos the status code it received"
CloseConnection(aCode, aReason);
// RFC 6455, 5.5.1: "When sending a Close frame in response, the endpoint
// typically echos the status code it received".
// But never send certain codes, per section 7.4.1
if (aCode == 1005 || aCode == 1006 || aCode == 1015) {
CloseConnection(0, EmptyCString());
} else {
CloseConnection(aCode, aReason);
}
} else {
// Nothing else to do: OnStop does the rest of the work.
NS_ASSERTION (mReadyState == nsIWebSocket::CLOSING, "unknown state");

View File

@ -459,6 +459,10 @@ WINDOW_ONLY_EVENT(deviceproximity,
NS_DEVICE_PROXIMITY,
EventNameType_None,
NS_EVENT)
WINDOW_ONLY_EVENT(userproximity,
NS_USER_PROXIMITY,
EventNameType_None,
NS_EVENT)
WINDOW_ONLY_EVENT(devicelight,
NS_DEVICE_LIGHT,
EventNameType_None,

View File

@ -94,6 +94,8 @@ NS_NewDOMPopupBlockedEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, n
nsresult
NS_NewDOMDeviceProximityEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent *aEvent);
nsresult
NS_NewDOMUserProximityEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent *aEvent);
nsresult
NS_NewDOMDeviceOrientationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
nsresult
NS_NewDOMDeviceLightEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);

View File

@ -66,6 +66,7 @@ CPPSRCS = \
nsDOMMutationEvent.cpp \
nsDOMPopupBlockedEvent.cpp \
nsDOMDeviceProximityEvent.cpp \
nsDOMUserProximityEvent.cpp \
nsDOMDeviceLightEvent.cpp \
nsDOMDeviceOrientationEvent.cpp \
nsDOMDeviceMotionEvent.cpp \

View File

@ -128,6 +128,7 @@ static const char* const sEventNames[] = {
"devicemotion",
"deviceorientation",
"deviceproximity",
"userproximity",
"devicelight"
};
@ -1557,6 +1558,8 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
return sEventNames[eDOMEvents_deviceorientation];
case NS_DEVICE_PROXIMITY:
return sEventNames[eDOMEvents_deviceproximity];
case NS_USER_PROXIMITY:
return sEventNames[eDOMEvents_userproximity];
case NS_DEVICE_LIGHT:
return sEventNames[eDOMEvents_devicelight];
case NS_FULLSCREENCHANGE:

View File

@ -211,6 +211,7 @@ public:
eDOMEvents_devicemotion,
eDOMEvents_deviceorientation,
eDOMEvents_deviceproximity,
eDOMEvents_userproximity,
eDOMEvents_devicelight
};

View File

@ -0,0 +1,57 @@
/* 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 "nsDOMUserProximityEvent.h"
#include "nsContentUtils.h"
#include "DictionaryHelpers.h"
NS_IMPL_ADDREF_INHERITED(nsDOMUserProximityEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMUserProximityEvent, nsDOMEvent)
DOMCI_DATA(UserProximityEvent, nsDOMUserProximityEvent)
NS_INTERFACE_MAP_BEGIN(nsDOMUserProximityEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMUserProximityEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(UserProximityEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMETHODIMP
nsDOMUserProximityEvent::InitUserProximityEvent(const nsAString & aEventTypeArg,
bool aCanBubbleArg,
bool aCancelableArg,
bool aNear)
{
nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
NS_ENSURE_SUCCESS(rv, rv);
mNear = aNear;
return NS_OK;
}
NS_IMETHODIMP
nsDOMUserProximityEvent::GetNear(bool *aNear)
{
NS_ENSURE_ARG_POINTER(aNear);
*aNear = mNear;
return NS_OK;
}
nsresult
nsDOMUserProximityEvent::InitFromCtor(const nsAString& aType,
JSContext* aCx, jsval* aVal)
{
mozilla::dom::UserProximityEventInit d;
nsresult rv = d.Init(aCx, aVal);
NS_ENSURE_SUCCESS(rv, rv);
return InitUserProximityEvent(aType, d.bubbles, d.cancelable, d.near);
}
nsresult
NS_NewDOMUserProximityEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsEvent *aEvent)
{
NS_ENSURE_ARG_POINTER(aInstancePtrResult);
nsDOMUserProximityEvent* it = new nsDOMUserProximityEvent(aPresContext, aEvent);
return CallQueryInterface(it, aInstancePtrResult);
}

View File

@ -0,0 +1,36 @@
/* 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 nsDOMUserProximityEvent_h__
#define nsDOMUserProximityEvent_h__
#include "nsIDOMUserProximityEvent.h"
#include "nsDOMEvent.h"
class nsDOMUserProximityEvent
: public nsDOMEvent
, public nsIDOMUserProximityEvent
{
public:
nsDOMUserProximityEvent(nsPresContext* aPresContext, nsEvent* aEvent)
: nsDOMEvent(aPresContext, aEvent),
mNear(false) {}
NS_DECL_ISUPPORTS_INHERITED
// Forward to nsDOMEvent
NS_FORWARD_TO_NSDOMEVENT
// nsIDOMUserProximityEvent Interface
NS_DECL_NSIDOMUSERPROXIMITYEVENT
virtual nsresult InitFromCtor(const nsAString& aType,
JSContext* aCx,
jsval* aVal);
protected:
bool mNear;
};
#endif

View File

@ -290,7 +290,7 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
}
} else if (aTypeAtom == nsGkAtoms::ondeviceorientation) {
EnableDevice(NS_DEVICE_ORIENTATION);
} else if (aTypeAtom == nsGkAtoms::ondeviceproximity) {
} else if (aTypeAtom == nsGkAtoms::ondeviceproximity || aTypeAtom == nsGkAtoms::onuserproximity) {
EnableDevice(NS_DEVICE_PROXIMITY);
} else if (aTypeAtom == nsGkAtoms::ondevicelight) {
EnableDevice(NS_DEVICE_LIGHT);
@ -351,6 +351,7 @@ nsEventListenerManager::EnableDevice(PRUint32 aType)
window->EnableDeviceSensor(SENSOR_ORIENTATION);
break;
case NS_DEVICE_PROXIMITY:
case NS_USER_PROXIMITY:
window->EnableDeviceSensor(SENSOR_PROXIMITY);
break;
case NS_DEVICE_LIGHT:
@ -387,6 +388,7 @@ nsEventListenerManager::DisableDevice(PRUint32 aType)
window->DisableDeviceSensor(SENSOR_GYROSCOPE);
break;
case NS_DEVICE_PROXIMITY:
case NS_USER_PROXIMITY:
window->DisableDeviceSensor(SENSOR_PROXIMITY);
break;
case NS_DEVICE_LIGHT:

View File

@ -2222,6 +2222,8 @@ nsEventStateManager::DetermineDragTarget(nsPresContext* aPresContext,
nsCOMPtr<nsISupports> container = aPresContext->GetContainer();
nsCOMPtr<nsIDOMWindow> window = do_GetInterface(container);
if (!window)
return;
// GetDragData determines if a selection, link or image in the content
// should be dragged, and places the data associated with the drag in the

View File

@ -379,6 +379,14 @@ is(e.max, 2, "max should be 2");
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
// UserProximityEvent
e = new UserProximityEvent("hello", {near: true});
ok(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.near, true, "near should be true");
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
// DeviceLightEvent
e = new DeviceLightEvent("hello", {value: 1} );
ok(e.type, "hello", "Wrong event type!");

View File

@ -50,7 +50,6 @@ _TEST_FILES = \
$(NULL)
_CHROME_FILES = \
test_bug330705-2.xul \
test_bug233643.xul \
test_bug398289.html \
398289-resource.xul \

View File

@ -1,50 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
title="Test for Bug 330705">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=330705
-->
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=330705">Mozilla Bug 330705</a>
<p id="display">
<box tabindex="1" style="-moz-user-focus:normal;" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
<box tabindex="1" style="-moz-user-focus:normal;" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
</p>
<div id="content" style="display: none">
<script class="testbody" type="text/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
var isFocused = false;
function doTest() {
document.getElementsByTagName('box')[1].blur();
setTimeout(function () {
ok(isFocused,
"The first box element is still focused after blur() has been called on the second box element");
SimpleTest.finish();
}, 0);
}
function onLoad() {
var box = document.getElementsByTagName('box')[0];
box.addEventListener('focus', function() {
isFocused = true;
setTimeout(doTest, 0);
box.removeEventListener('focus', arguments.callee, true);
}, true);
box.addEventListener('blur', function() { isFocused = false;}, true);
box.focus();
}
addLoadEvent(onLoad);
]]>
</script>
<pre id="test">
</pre>
</div>
</body>
</window>

View File

@ -326,6 +326,7 @@
#include "nsIDOMCSSStyleSheet.h"
#include "nsDOMCSSValueList.h"
#include "nsIDOMDeviceProximityEvent.h"
#include "nsIDOMUserProximityEvent.h"
#include "nsIDOMDeviceLightEvent.h"
#include "nsIDOMDeviceOrientationEvent.h"
#include "nsIDOMDeviceMotionEvent.h"
@ -821,6 +822,9 @@ static nsDOMClassInfoData sClassInfoData[] = {
// Device Proximity
NS_DEFINE_CLASSINFO_DATA(DeviceProximityEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// User Proximity
NS_DEFINE_CLASSINFO_DATA(UserProximityEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// Device Orientation
NS_DEFINE_CLASSINFO_DATA(DeviceOrientationEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -1697,6 +1701,7 @@ NS_DEFINE_EVENT_CTOR(UIEvent)
NS_DEFINE_EVENT_CTOR(MouseEvent)
NS_DEFINE_EVENT_CTOR(DeviceLightEvent)
NS_DEFINE_EVENT_CTOR(DeviceProximityEvent)
NS_DEFINE_EVENT_CTOR(UserProximityEvent)
nsresult
NS_DOMStorageEventCtor(nsISupports** aInstancePtrResult)
@ -1732,6 +1737,7 @@ static const nsConstructorFuncMapData kConstructorFuncMap[] =
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(DeviceProximityEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UserProximityEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(DeviceLightEvent)
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(StorageEvent)
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, sms::SmsFilter::NewSmsFilter)
@ -2621,6 +2627,11 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(UserProximityEvent, nsIDOMUserProximityEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMUserProximityEvent)
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(DeviceOrientationEvent, nsIDOMDeviceOrientationEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceOrientationEvent)
DOM_CLASSINFO_EVENT_MAP_ENTRIES

View File

@ -81,6 +81,7 @@ DOMCI_CLASS(CompositionEvent)
DOMCI_CLASS(PopupBlockedEvent)
DOMCI_CLASS(DeviceLightEvent)
DOMCI_CLASS(DeviceProximityEvent)
DOMCI_CLASS(UserProximityEvent)
DOMCI_CLASS(DeviceOrientationEvent)
DOMCI_CLASS(DeviceMotionEvent)
DOMCI_CLASS(DeviceAcceleration)

View File

@ -69,7 +69,7 @@ interface nsIDOMMozURLProperty : nsISupports
* @see <http://www.whatwg.org/html/#window>
*/
[scriptable, uuid(e6198a86-1a46-46ec-9501-dfcd84a5f630)]
[scriptable, uuid(a89569e6-4fef-49a5-a19b-612ac481fa2e)]
interface nsIDOMWindow : nsISupports
{
// the current browsing context
@ -465,6 +465,7 @@ interface nsIDOMWindow : nsISupports
[implicit_jscontext] attribute jsval ondevicemotion;
[implicit_jscontext] attribute jsval ondeviceorientation;
[implicit_jscontext] attribute jsval ondeviceproximity;
[implicit_jscontext] attribute jsval onuserproximity;
[implicit_jscontext] attribute jsval ondevicelight;
[implicit_jscontext] attribute jsval onmouseenter;

View File

@ -77,6 +77,7 @@ XPIDLSRCS = \
nsIDOMMozTouchEvent.idl \
nsIDOMDeviceLightEvent.idl \
nsIDOMDeviceProximityEvent.idl \
nsIDOMUserProximityEvent.idl \
nsIDOMDeviceOrientationEvent.idl \
nsIDOMDeviceMotionEvent.idl \
nsIDOMScrollAreaEvent.idl \

View File

@ -0,0 +1,21 @@
/* 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 "nsIDOMEvent.idl"
[scriptable, uuid(e67432b8-ead4-4247-bf6c-f2e426472478)]
interface nsIDOMUserProximityEvent : nsIDOMEvent
{
[noscript] void initUserProximityEvent(in DOMString eventTypeArg,
in boolean canBubbleArg,
in boolean cancelableArg,
in boolean near);
readonly attribute boolean near;
};
dictionary UserProximityEventInit : EventInit
{
boolean near;
};

View File

@ -54,6 +54,8 @@
using namespace mozilla;
using namespace hal;
#undef near
// also see sDefaultSensorHint in mobile/android/base/GeckoAppShell.java
#define DEFAULT_SENSOR_POLL 100
@ -124,6 +126,7 @@ NS_IMPL_ISUPPORTS1(nsDeviceSensors, nsIDeviceSensors)
nsDeviceSensors::nsDeviceSensors()
{
mIsUserProximityNear = false;
mLastDOMMotionEventTime = TimeStamp::Now();
mEnabled = Preferences::GetBool("device.sensors.enabled", true);
@ -274,14 +277,46 @@ nsDeviceSensors::FireDOMProximityEvent(nsIDOMEventTarget *aTarget,
}
bool defaultActionEnabled;
aTarget->DispatchEvent(event, &defaultActionEnabled);
// Some proximity sensors only support a binary near or
// far measurement. In this case, the sensor should report
// its maximum range value in the far state and a lesser
// value in the near state.
bool near = (aValue < aMax);
if (mIsUserProximityNear != near) {
mIsUserProximityNear = near;
FireDOMUserProximityEvent(aTarget, mIsUserProximityNear);
}
}
void
nsDeviceSensors::FireDOMUserProximityEvent(nsIDOMEventTarget *aTarget, bool aNear)
{
nsCOMPtr<nsIDOMEvent> event;
NS_NewDOMUserProximityEvent(getter_AddRefs(event), nsnull, nsnull);
nsCOMPtr<nsIDOMUserProximityEvent> pe = do_QueryInterface(event);
pe->InitUserProximityEvent(NS_LITERAL_STRING("userproximity"),
true,
false,
aNear);
nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
privateEvent = do_QueryInterface(event);
if (privateEvent) {
privateEvent->SetTrusted(true);
}
bool defaultActionEnabled;
aTarget->DispatchEvent(event, &defaultActionEnabled);
}
void
nsDeviceSensors::FireDOMOrientationEvent(nsIDOMDocument *domdoc,
nsIDOMEventTarget *target,
double alpha,
double beta,
double gamma)
nsIDOMEventTarget *target,
double alpha,
double beta,
double gamma)
{
nsCOMPtr<nsIDOMEvent> event;
bool defaultActionEnabled = true;

View File

@ -46,6 +46,7 @@
#include "nsIDOMDeviceLightEvent.h"
#include "nsIDOMDeviceOrientationEvent.h"
#include "nsIDOMDeviceProximityEvent.h"
#include "nsIDOMUserProximityEvent.h"
#include "nsIDOMDeviceMotionEvent.h"
#include "nsDOMDeviceMotionEvent.h"
#include "mozilla/TimeStamp.h"
@ -84,6 +85,9 @@ private:
double aMin,
double aMax);
void FireDOMUserProximityEvent(nsIDOMEventTarget *aTarget,
bool aNear);
void FireDOMOrientationEvent(class nsIDOMDocument *domDoc,
class nsIDOMEventTarget *target,
double alpha,
@ -104,6 +108,7 @@ private:
}
mozilla::TimeStamp mLastDOMMotionEventTime;
bool mIsUserProximityNear;
nsRefPtr<nsDOMDeviceAcceleration> mLastAcceleration;
nsRefPtr<nsDOMDeviceAcceleration> mLastAccelerationIncluduingGravity;
nsRefPtr<nsDOMDeviceRotationRate> mLastRotationRate;

View File

@ -491,7 +491,9 @@ function startTest()
ok(gEvents === "", "focusing element that is already focused");
$("t2").blur();
$("t7").blur();
ok(gEvents === "", "blurring element that is not focused");
is(document.activeElement, $("t1"), "old element still focused after blur() on another element");
// focus() method on elements that are not tabbable
for (idx = 1; idx <= kFocusSteps; idx++) {

File diff suppressed because it is too large Load Diff

View File

@ -65,6 +65,8 @@ struct PRLogModuleInfo;
# define MOZ_LAYERS_LOG(_args)
#endif // if defined(DEBUG) || defined(PR_LOGGING)
#define MOZ_ENABLE_MASK_LAYERS
class gfxContext;
class nsPaintEvent;
@ -719,6 +721,7 @@ public:
*/
void SetMaskLayer(Layer* aMaskLayer)
{
#ifdef MOZ_ENABLE_MASK_LAYERS
#ifdef DEBUG
if (aMaskLayer) {
gfxMatrix maskTransform;
@ -730,6 +733,7 @@ public:
mMaskLayer = aMaskLayer;
Mutated();
#endif
}
/**

View File

@ -64,6 +64,46 @@ struct TypeInferenceSizes
size_t temporary;
};
// These measurements relate directly to the JSRuntime, and not to
// compartments within it.
struct RuntimeSizes
{
RuntimeSizes()
: object(0)
, atomsTable(0)
, contexts(0)
, dtoa(0)
, temporary(0)
, mjitCode(0)
, regexpCode(0)
, unusedCodeMemory(0)
, stackCommitted(0)
, gcMarker(0)
, mathCache(0)
, scriptFilenames(0)
, compartmentObjects(0)
{}
size_t object;
size_t atomsTable;
size_t contexts;
size_t dtoa;
size_t temporary;
size_t mjitCode;
size_t regexpCode;
size_t unusedCodeMemory;
size_t stackCommitted;
size_t gcMarker;
size_t mathCache;
size_t scriptFilenames;
// This is the exception to the "RuntimeSizes doesn't measure things within
// compartments" rule. We combine the sizes of all the JSCompartment
// objects into a single measurement because each one is fairly small, and
// they're all the same size.
size_t compartmentObjects;
};
struct CompartmentStats
{
CompartmentStats() {
@ -95,6 +135,7 @@ struct CompartmentStats
size_t shapesCompartmentTables;
size_t scriptData;
size_t mjitData;
size_t crossCompartmentWrappers;
TypeInferenceSizes typeInferenceSizes;
};
@ -102,16 +143,7 @@ struct CompartmentStats
struct RuntimeStats
{
RuntimeStats(JSMallocSizeOfFun mallocSizeOf)
: runtimeObject(0)
, runtimeAtomsTable(0)
, runtimeContexts(0)
, runtimeNormal(0)
, runtimeTemporary(0)
, runtimeMjitCode(0)
, runtimeRegexpCode(0)
, runtimeUnusedCodeMemory(0)
, runtimeStackCommitted(0)
, runtimeGCMarker(0)
: runtime()
, gcHeapChunkTotal(0)
, gcHeapCommitted(0)
, gcHeapUnused(0)
@ -133,16 +165,8 @@ struct RuntimeStats
, mallocSizeOf(mallocSizeOf)
{}
size_t runtimeObject;
size_t runtimeAtomsTable;
size_t runtimeContexts;
size_t runtimeNormal;
size_t runtimeTemporary;
size_t runtimeMjitCode;
size_t runtimeRegexpCode;
size_t runtimeUnusedCodeMemory;
size_t runtimeStackCommitted;
size_t runtimeGCMarker;
js::RuntimeSizes runtime;
size_t gcHeapChunkTotal;
size_t gcHeapCommitted;
size_t gcHeapUnused;

View File

@ -69,6 +69,8 @@ StatsCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment)
// Get the compartment-level numbers.
compartment->sizeOfTypeInferenceData(&cStats.typeInferenceSizes, rtStats->mallocSizeOf);
cStats.shapesCompartmentTables = compartment->sizeOfShapeTable(rtStats->mallocSizeOf);
cStats.crossCompartmentWrappers =
compartment->crossCompartmentWrappers.sizeOfExcludingThis(rtStats->mallocSizeOf);
}
static void
@ -195,23 +197,8 @@ CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats)
StatsArenaCallback, StatsCellCallback);
IterateChunks(rt, rtStats, StatsChunkCallback);
rtStats->runtimeObject = rtStats->mallocSizeOf(rt);
rt->sizeOfIncludingThis(rtStats->mallocSizeOf, &rtStats->runtime);
rt->sizeOfExcludingThis(rtStats->mallocSizeOf,
&rtStats->runtimeNormal,
&rtStats->runtimeTemporary,
&rtStats->runtimeMjitCode,
&rtStats->runtimeRegexpCode,
&rtStats->runtimeUnusedCodeMemory,
&rtStats->runtimeStackCommitted,
&rtStats->runtimeGCMarker);
rtStats->runtimeAtomsTable =
rt->atomState.atoms.sizeOfExcludingThis(rtStats->mallocSizeOf);
for (ContextIter acx(rt); !acx.done(); acx.next())
rtStats->runtimeContexts += acx->sizeOfIncludingThis(rtStats->mallocSizeOf);
// This is initialized to all bytes stored in used chunks, and then we
// subtract used space from it each time around the loop.
rtStats->gcHeapChunkDirtyUnused = rtStats->gcHeapChunkTotal -
@ -219,7 +206,7 @@ CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats)
rtStats->gcHeapChunkCleanDecommitted -
rtStats->gcHeapChunkDirtyDecommitted;
rtStats->totalMjit = rtStats->runtimeMjitCode;
rtStats->totalMjit = rtStats->runtime.mjitCode;
for (size_t index = 0;
index < rtStats->compartmentStatsVector.length();
@ -293,19 +280,7 @@ GetExplicitNonHeapForRuntime(JSRuntime *rt, JSMallocSizeOfFun mallocSizeOf)
// explicit/runtime/regexp-code
// explicit/runtime/stack-committed
// explicit/runtime/unused-code-memory
size_t dummy, mjitCode, regexpCode, unusedCodeMemory, stackCommitted;
rt->sizeOfExcludingThis(mallocSizeOf,
&dummy,
&dummy,
&mjitCode,
&regexpCode,
&unusedCodeMemory,
&stackCommitted,
NULL);
n += mjitCode;
n += regexpCode;
n += unusedCodeMemory;
n += stackCommitted;
n += rt->sizeOfExplicitNonHeap();
return int64_t(n);
}

View File

@ -10,6 +10,7 @@
#include "jsfriendapi.h"
#include "jsgc.h"
#include "jsobj.h"
#include "jsobjinlines.h"
#include "jsprf.h"
#include "jswrapper.h"
@ -142,6 +143,22 @@ GCParameter(JSContext *cx, unsigned argc, jsval *vp)
return true;
}
static JSBool
IsProxy(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (argc != 1) {
JS_ReportError(cx, "the function takes exactly one argument");
return false;
}
if (!args[0].isObject()) {
args.rval().setBoolean(false);
return true;
}
args.rval().setBoolean(args[0].toObject().isProxy());
return true;
}
static JSBool
InternalConst(JSContext *cx, unsigned argc, jsval *vp)
{
@ -583,6 +600,10 @@ static JSFunctionSpecWithHelp TestingFunctions[] = {
" Query an internal constant for the engine. See InternalConst source for\n"
" the list of constant names."),
JS_FN_HELP("isProxy", IsProxy, 1, 0,
"isProxy(obj)",
" If true, obj is a proxy of some sort"),
JS_FN_HELP("mjitChunkLimit", MJitChunkLimit, 1, 0,
"mjitChunkLimit(N)",
" Specify limit on compiled chunk size during mjit compilation."),

View File

@ -157,8 +157,9 @@ frontend::CompileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
/* If this is a direct call to eval, inherit the caller's strictness. */
if (callerFrame &&
callerFrame->isScriptFrame() &&
callerFrame->script()->strictModeCode) {
bce.sc->flags |= TCF_STRICT_MODE_CODE;
callerFrame->script()->strictModeCode)
{
bce.sc->setInStrictMode();
tokenStream.setStrictMode();
}

View File

@ -127,7 +127,6 @@ BytecodeEmitter::BytecodeEmitter(Parser *parser, SharedContext *sc, unsigned lin
bool
BytecodeEmitter::init()
{
roLexdeps.init();
return constMap.init() && atomIndices.ensureMap(sc->context);
}
@ -1000,7 +999,7 @@ BytecodeEmitter::noteClosedVar(ParseNode *pn)
for (size_t i = 0; i < closedVars.length(); ++i)
JS_ASSERT(closedVars[i] != pn->pn_cookie.slot());
#endif
sc->flags |= TCF_FUN_HEAVYWEIGHT;
sc->setFunIsHeavyweight();
return closedVars.append(pn->pn_cookie.slot());
}
@ -1015,7 +1014,7 @@ BytecodeEmitter::noteClosedArg(ParseNode *pn)
for (size_t i = 0; i < closedArgs.length(); ++i)
JS_ASSERT(closedArgs[i] != pn->pn_cookie.slot());
#endif
sc->flags |= TCF_FUN_HEAVYWEIGHT;
sc->setFunIsHeavyweight();
return closedArgs.append(pn->pn_cookie.slot());
}
@ -1090,7 +1089,7 @@ EmitEnterBlock(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
* clones must get unique shapes; see the comments for
* js::Bindings::extensibleParents.
*/
if ((bce->sc->flags & TCF_FUN_EXTENSIBLE_SCOPE) ||
if (bce->sc->funHasExtensibleScope() ||
bce->sc->bindings.extensibleParents()) {
Shape *newShape = Shape::setExtensibleParents(cx, blockObj->lastProperty());
if (!newShape)
@ -1127,9 +1126,9 @@ TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op)
{
if (bce->parser->compileAndGo &&
bce->globalScope->globalObj &&
!bce->sc->mightAliasLocals() &&
!bce->sc->funMightAliasLocals() &&
!pn->isDeoptimized() &&
!(bce->sc->flags & TCF_STRICT_MODE_CODE)) {
!bce->sc->inStrictMode()) {
switch (*op) {
case JSOP_NAME: *op = JSOP_GETGNAME; break;
case JSOP_SETNAME: *op = JSOP_SETGNAME; break;
@ -1356,7 +1355,7 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* the scope chain so that assignment will throw a TypeError.
*/
JS_ASSERT(op != JSOP_DELNAME);
if (!(bce->sc->flags & TCF_FUN_HEAVYWEIGHT)) {
if (!bce->sc->funIsHeavyweight()) {
op = JSOP_CALLEE;
pn->pn_dflags |= PND_CONST;
}
@ -2618,7 +2617,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
* execution starts from script->code, so this has no semantic effect.
*/
if (bce->sc->argumentsHasLocalBinding()) {
if (bce->sc->funArgumentsHasLocalBinding()) {
JS_ASSERT(bce->next() == bce->base()); /* See JSScript::argumentsBytecode. */
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
@ -2637,7 +2636,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
bce->switchToMain();
}
if (bce->sc->flags & TCF_FUN_IS_GENERATOR) {
if (bce->sc->funIsGenerator()) {
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
return false;
@ -2663,7 +2662,7 @@ MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *
}
if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
(!bce->sc->inFunction || (bce->sc->flags & TCF_FUN_HEAVYWEIGHT)))
(!bce->sc->inFunction || bce->sc->funIsHeavyweight()))
{
bce->switchToProlog();
if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
@ -4827,7 +4826,7 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return EmitFunctionDefNop(cx, bce, pn->pn_index);
}
JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
JS_ASSERT_IF(pn->pn_funbox->funIsHeavyweight(),
fun->kind() == JSFUN_INTERPRETED);
{
@ -4837,10 +4836,14 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (!bce2.init())
return false;
bce2.sc->flags = pn->pn_funbox->tcflags | (bce->sc->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
bce2.sc->bindings.transfer(cx, &pn->pn_funbox->bindings);
FunctionBox *funbox = pn->pn_funbox;
bce2.sc->cxFlags = funbox->cxFlags;
if (bce->sc->funMightAliasLocals())
bce2.sc->setFunMightAliasLocals(); // inherit funMightAliasLocals from parent
bce2.sc->bindings.transfer(cx, &funbox->bindings);
bce2.sc->setFunction(fun);
bce2.sc->funbox = pn->pn_funbox;
bce2.sc->funbox = funbox;
bce2.parent = bce;
bce2.globalScope = bce->globalScope;
@ -4863,7 +4866,7 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
/* Emit a bytecode pointing to the closure object in its immediate. */
if (pn->getOp() != JSOP_NOP) {
if ((pn->pn_funbox->inGenexpLambda) && NewSrcNote(cx, bce, SRC_GENEXP) < 0)
if (pn->pn_funbox->inGenexpLambda && NewSrcNote(cx, bce, SRC_GENEXP) < 0)
return false;
return EmitFunctionOp(cx, pn->getOp(), index, bce);
@ -5925,9 +5928,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
case PNK_UPVARS:
JS_ASSERT(pn->pn_names->count() != 0);
bce->roLexdeps = pn->pn_names;
ok = EmitTree(cx, bce, pn->pn_tree);
bce->roLexdeps.clearMap();
pn->pn_names.releaseMap(cx);
break;

View File

@ -123,7 +123,6 @@ struct BytecodeEmitter
Parser *parser; /* the parser */
OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
AtomDefnMapPtr roLexdeps;
unsigned firstLine; /* first line, for JSScript::NewScriptFromEmitter */
int stackDepth; /* current stack depth in script frame */

View File

@ -39,6 +39,7 @@
* ***** END LICENSE BLOCK ***** */
#include "frontend/ParseNode.h"
#include "frontend/Parser.h"
#include "jsscriptinlines.h"
@ -112,18 +113,12 @@ bool
FunctionBox::inAnyDynamicScope() const
{
for (const FunctionBox *funbox = this; funbox; funbox = funbox->parent) {
if (funbox->inWith || (funbox->tcflags & TCF_FUN_EXTENSIBLE_SCOPE))
if (funbox->inWith || funbox->funHasExtensibleScope())
return true;
}
return false;
}
bool
FunctionBox::scopeIsExtensible() const
{
return tcflags & TCF_FUN_EXTENSIBLE_SCOPE;
}
/* Add |node| to |parser|'s free node list. */
void
ParseNodeAllocator::freeNode(ParseNode *pn)

View File

@ -47,6 +47,7 @@
#include "frontend/ParseMaps.h"
#include "frontend/TokenStream.h"
#include "frontend/TreeContext.h"
namespace js {
@ -1528,24 +1529,35 @@ struct ObjectBox {
ObjectBox *emitLink;
JSObject *object;
bool isFunctionBox;
ObjectBox(ObjectBox *traceLink, JSObject *obj);
};
#define JSFB_LEVEL_BITS 14
struct FunctionBox : public ObjectBox
{
ParseNode *node;
FunctionBox *siblings;
FunctionBox *kids;
FunctionBox *parent;
Bindings bindings; /* bindings for this function */
uint32_t queued:1,
inLoop:1, /* in a loop in parent function */
level:JSFB_LEVEL_BITS;
uint32_t tcflags;
bool inWith:1; /* some enclosing scope is a with-statement
or E4X filter-expression */
bool inGenexpLambda:1; /* lambda from generator expression */
ParseNode *node;
FunctionBox *siblings;
FunctionBox *kids;
FunctionBox *parent;
Bindings bindings; /* bindings for this function */
uint32_t level:JSFB_LEVEL_BITS;
bool queued:1;
bool inLoop:1; /* in a loop in parent function */
bool inWith:1; /* some enclosing scope is a with-statement
or E4X filter-expression */
bool inGenexpLambda:1; /* lambda from generator expression */
ContextFlags cxFlags;
FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseNode *fn, TreeContext *tc);
bool funIsHeavyweight() const { return cxFlags.funIsHeavyweight; }
bool funIsGenerator() const { return cxFlags.funIsGenerator; }
bool funHasExtensibleScope() const { return cxFlags.funHasExtensibleScope; }
void setFunIsHeavyweight() { cxFlags.funIsHeavyweight = true; }
JSFunction *function() const { return (JSFunction *) object; }
@ -1554,12 +1566,6 @@ struct FunctionBox : public ObjectBox
* filter-expression, or a function that uses direct eval.
*/
bool inAnyDynamicScope() const;
/*
* Must this function's descendants be marked as having an extensible
* ancestor?
*/
bool scopeIsExtensible() const;
};
struct FunctionBoxQueue {

View File

@ -117,9 +117,7 @@ Parser::Parser(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin,
principals(NULL),
originPrincipals(NULL),
callerFrame(cfp),
callerVarObj(cfp ? &cfp->varObj() : NULL),
allocator(cx),
functionCount(0),
traceListHead(NULL),
tc(NULL),
keepAtoms(cx->runtime),
@ -127,7 +125,6 @@ Parser::Parser(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin,
compileAndGo(compileAndGo)
{
cx->activeCompilations++;
PodArrayZero(tempFreeList);
setPrincipals(prin, originPrin);
JS_ASSERT_IF(cfp, cfp->isScriptFrame());
}
@ -172,6 +169,14 @@ Parser::setPrincipals(JSPrincipals *prin, JSPrincipals *originPrin)
JS_HoldPrincipals(originPrincipals);
}
ObjectBox::ObjectBox(ObjectBox* traceLink, JSObject *obj)
: traceLink(traceLink),
emitLink(NULL),
object(obj),
isFunctionBox(false)
{
}
ObjectBox *
Parser::newObjectBox(JSObject *obj)
{
@ -184,19 +189,49 @@ Parser::newObjectBox(JSObject *obj)
* scanning, parsing and code generation for the whole script or top-level
* function.
*/
ObjectBox *objbox = context->tempLifoAlloc().new_<ObjectBox>();
ObjectBox *objbox = context->tempLifoAlloc().new_<ObjectBox>(traceListHead, obj);
if (!objbox) {
js_ReportOutOfMemory(context);
return NULL;
}
objbox->traceLink = traceListHead;
traceListHead = objbox;
objbox->emitLink = NULL;
objbox->object = obj;
objbox->isFunctionBox = false;
return objbox;
}
FunctionBox::FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseNode *fn, TreeContext *tc)
: ObjectBox(traceListHead, obj),
node(fn),
siblings(tc->sc->functionList),
kids(NULL),
parent(tc->sc->funbox),
bindings(tc->sc->context),
level(tc->sc->staticLevel),
queued(false),
inLoop(false),
inWith(!!tc->innermostWith),
inGenexpLambda(false),
cxFlags(tc->sc->context) // the cxFlags are set in LeaveFunction
{
isFunctionBox = true;
for (StmtInfo *stmt = tc->sc->topStmt; stmt; stmt = stmt->down) {
if (STMT_IS_LOOP(stmt)) {
inLoop = true;
break;
}
}
if (!tc->sc->inFunction) {
JSObject *scope = tc->sc->scopeChain();
while (scope) {
if (scope->isWith())
inWith = true;
scope = scope->enclosingScope();
}
}
}
FunctionBox *
Parser::newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc)
{
@ -210,43 +245,14 @@ Parser::newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc)
* scanning, parsing and code generation for the whole script or top-level
* function.
*/
FunctionBox *funbox = context->tempLifoAlloc().newPod<FunctionBox>();
FunctionBox *funbox = context->tempLifoAlloc().new_<FunctionBox>(traceListHead, obj, fn, tc);
if (!funbox) {
js_ReportOutOfMemory(context);
return NULL;
}
funbox->traceLink = traceListHead;
traceListHead = funbox;
funbox->emitLink = NULL;
funbox->object = obj;
funbox->isFunctionBox = true;
funbox->node = fn;
funbox->siblings = tc->sc->functionList;
tc->sc->functionList = funbox;
++functionCount;
funbox->kids = NULL;
funbox->parent = tc->sc->funbox;
new (&funbox->bindings) Bindings(context);
funbox->queued = false;
funbox->inLoop = false;
for (StmtInfo *stmt = tc->sc->topStmt; stmt; stmt = stmt->down) {
if (STMT_IS_LOOP(stmt)) {
funbox->inLoop = true;
break;
}
}
funbox->level = tc->sc->staticLevel;
funbox->tcflags = tc->sc->flags & TCF_STRICT_MODE_CODE;
funbox->inWith = !!tc->innermostWith;
if (!tc->sc->inFunction) {
JSObject *scope = tc->sc->scopeChain();
while (scope) {
if (scope->isWith())
funbox->inWith = true;
scope = scope->enclosingScope();
}
}
funbox->inGenexpLambda = false;
traceListHead = tc->sc->functionList = funbox;
return funbox;
}
@ -605,7 +611,6 @@ Parser::functionBody(FunctionBodyType type)
PushStatement(tc->sc, &stmtInfo, STMT_BLOCK, -1);
stmtInfo.flags = SIF_BODY_BLOCK;
unsigned oldflags = tc->sc->flags;
JS_ASSERT(!tc->hasReturnExpr && !tc->hasReturnVoid);
ParseNode *pn;
@ -620,7 +625,7 @@ Parser::functionBody(FunctionBodyType type)
if (!pn->pn_kid) {
pn = NULL;
} else {
if (tc->sc->flags & TCF_FUN_IS_GENERATOR) {
if (tc->sc->funIsGenerator()) {
ReportBadReturn(context, this, pn, JSREPORT_ERROR,
JSMSG_BAD_GENERATOR_RETURN,
JSMSG_BAD_ANON_GENERATOR_RETURN);
@ -666,16 +671,16 @@ Parser::functionBody(FunctionBodyType type)
for (FuncStmtSet::Range r = set->all(); !r.empty(); r.popFront()) {
PropertyName *name = r.front()->asPropertyName();
if (name == arguments)
tc->sc->noteBindingsAccessedDynamically();
tc->sc->setBindingsAccessedDynamically();
else if (Definition *dn = tc->decls.lookupFirst(name))
dn->pn_dflags |= PND_CLOSED;
}
}
/*
* As explained by the TCF_ARGUMENTS_HAS_LOCAL_BINDING comment, turn uses
* of 'arguments' into bindings. Use of 'arguments' should never escape a
* nested function as an upvar.
* As explained by the ContextFlags::funArgumentsHasLocalBinding comment,
* turn uses of 'arguments' into bindings. Use of 'arguments' should never
* escape a nested function as an upvar.
*/
for (AtomDefnRange r = tc->lexdeps->all(); !r.empty(); r.popFront()) {
JSAtom *atom = r.front().key();
@ -713,11 +718,11 @@ Parser::functionBody(FunctionBodyType type)
*/
BindingKind bindKind = tc->sc->bindings.lookup(context, arguments, NULL);
if (bindKind == VARIABLE || bindKind == CONSTANT) {
tc->sc->noteArgumentsHasLocalBinding();
tc->sc->setFunArgumentsHasLocalBinding();
/* Dynamic scope access destroys all hope of optimization. */
if (tc->sc->bindingsAccessedDynamically())
tc->sc->noteDefinitelyNeedsArgsObj();
tc->sc->setFunDefinitelyNeedsArgsObj();
/*
* Check whether any parameters have been assigned within this
@ -730,14 +735,13 @@ Parser::functionBody(FunctionBodyType type)
AtomDeclsIter iter(&tc->decls);
while (Definition *dn = iter.next()) {
if (dn->kind() == Definition::ARG && dn->isAssigned()) {
tc->sc->noteDefinitelyNeedsArgsObj();
tc->sc->setFunDefinitelyNeedsArgsObj();
break;
}
}
}
}
tc->sc->flags = oldflags | (tc->sc->flags & TCF_FUN_FLAGS);
return pn;
}
@ -1085,24 +1089,23 @@ EnterFunction(ParseNode *fn, Parser *parser, JSAtom *funAtom = NULL,
FunctionSyntaxKind kind = Expression)
{
TreeContext *funtc = parser->tc;
TreeContext *tc = funtc->parent;
JSFunction *fun = parser->newFunction(tc, funAtom, kind);
TreeContext *outertc = funtc->parent;
JSFunction *fun = parser->newFunction(outertc, funAtom, kind);
if (!fun)
return NULL;
/* Create box for fun->object early to protect against last-ditch GC. */
FunctionBox *funbox = parser->newFunctionBox(fun, fn, tc);
FunctionBox *funbox = parser->newFunctionBox(fun, fn, outertc);
if (!funbox)
return NULL;
/* Initialize non-default members of funtc. */
funtc->sc->flags |= funbox->tcflags;
funtc->sc->blockidGen = tc->sc->blockidGen;
/* Initialize non-default members of funtc->sc. */
funtc->sc->blockidGen = outertc->sc->blockidGen;
if (!GenerateBlockId(funtc->sc, funtc->sc->bodyid))
return NULL;
funtc->sc->setFunction(fun);
funtc->sc->funbox = funbox;
if (!SetStaticLevel(funtc->sc, tc->sc->staticLevel + 1))
if (!SetStaticLevel(funtc->sc, outertc->sc->staticLevel + 1))
return NULL;
return funbox;
@ -1140,7 +1143,7 @@ LeaveFunction(ParseNode *fn, Parser *parser, PropertyName *funName = NULL,
tc->sc->blockidGen = funtc->sc->blockidGen;
FunctionBox *funbox = fn->pn_funbox;
funbox->tcflags |= funtc->sc->flags & TCF_FUN_FLAGS;
funbox->cxFlags = funtc->sc->cxFlags; // copy all the flags
fn->pn_dflags |= PND_INITIALIZED;
if (!tc->sc->topStmt || tc->sc->topStmt->type == STMT_BLOCK)
@ -1542,6 +1545,9 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
if (!funbox)
return NULL;
if (outertc->sc->inStrictMode())
funsc.setInStrictMode(); // inherit strict mode from parent
RootedVarFunction fun(context, funbox->function());
/* Now parse formal argument list and compute fun->nargs. */
@ -1619,7 +1625,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
* parents: any local can be read at runtime.
*/
if (funsc.bindingsAccessedDynamically())
outertc->sc->noteBindingsAccessedDynamically();
outertc->sc->setBindingsAccessedDynamically();
#if JS_HAS_DESTRUCTURING
/*
@ -1662,9 +1668,9 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
* visible eval call, or assignment to 'arguments'), flag the function as
* heavyweight (requiring a call object per invocation).
*/
if (funsc.flags & TCF_FUN_HEAVYWEIGHT) {
if (funsc.funIsHeavyweight()) {
fun->flags |= JSFUN_HEAVYWEIGHT;
outertc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
outertc->sc->setFunIsHeavyweight();
}
JSOp op = JSOP_NOP;
@ -1680,12 +1686,12 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
*/
JS_ASSERT(!outertc->sc->inStrictMode());
op = JSOP_DEFFUN;
outertc->sc->noteMightAliasLocals();
outertc->sc->noteHasExtensibleScope();
outertc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
outertc->sc->setFunMightAliasLocals();
outertc->sc->setFunHasExtensibleScope();
outertc->sc->setFunIsHeavyweight();
/*
* Instead of noteBindingsAccessedDynamically, which would be
* Instead of setting bindingsAccessedDynamically, which would be
* overly conservative, remember the names of all function
* statements and mark any bindings with the same as aliased at the
* end of functionBody.
@ -1821,7 +1827,7 @@ Parser::recognizeDirectivePrologue(ParseNode *pn, bool *isDirectivePrologueMembe
return false;
}
tc->sc->flags |= TCF_STRICT_MODE_CODE;
tc->sc->setInStrictMode();
tokenStream.setStrictMode();
}
}
@ -1887,7 +1893,7 @@ Parser::statements(bool *hasFunctionStmt)
* General deoptimization was done in functionDef, here we just
* need to tell TOK_LC in Parser::statement to add braces.
*/
JS_ASSERT(tc->sc->hasExtensibleScope());
JS_ASSERT(tc->sc->funHasExtensibleScope());
if (hasFunctionStmt)
*hasFunctionStmt = true;
}
@ -2124,7 +2130,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
if (stmt && stmt->type == STMT_WITH) {
data->fresh = false;
pn->pn_dflags |= PND_DEOPTIMIZED;
tc->sc->noteMightAliasLocals();
tc->sc->setFunMightAliasLocals();
return true;
}
@ -2308,7 +2314,7 @@ NoteLValue(JSContext *cx, ParseNode *pn, SharedContext *sc, unsigned dflag = PND
* happens by making such functions heavyweight.
*/
if (sc->inFunction && pn->pn_atom == sc->fun()->atom)
sc->flags |= TCF_FUN_HEAVYWEIGHT;
sc->setFunIsHeavyweight();
}
static bool
@ -2660,7 +2666,7 @@ Parser::returnOrYield(bool useAssignExpr)
* a |for| token, so we have to delay flagging the current function.
*/
if (tc->parenDepth == 0) {
tc->sc->flags |= TCF_FUN_IS_GENERATOR;
tc->sc->setFunIsGenerator();
} else {
tc->yieldCount++;
tc->yieldNode = pn;
@ -2697,7 +2703,7 @@ Parser::returnOrYield(bool useAssignExpr)
tc->hasReturnVoid = true;
}
if (tc->hasReturnExpr && (tc->sc->flags & TCF_FUN_IS_GENERATOR)) {
if (tc->hasReturnExpr && tc->sc->funIsGenerator()) {
/* As in Python (see PEP-255), disallow return v; in generators. */
ReportBadReturn(context, this, pn, JSREPORT_ERROR,
JSMSG_BAD_GENERATOR_RETURN,
@ -3607,7 +3613,7 @@ Parser::withStatement()
* doesn't even merit a warning under JSOPTION_STRICT. See
* https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
*/
if (tc->sc->flags & TCF_STRICT_MODE_CODE) {
if (tc->sc->inStrictMode()) {
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_STRICT_CODE_WITH);
return NULL;
}
@ -3635,8 +3641,8 @@ Parser::withStatement()
pn->pn_pos.end = pn2->pn_pos.end;
pn->pn_right = pn2;
tc->sc->noteBindingsAccessedDynamically();
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->setBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
tc->innermostWith = oldWith;
/*
@ -4121,7 +4127,7 @@ Parser::statement()
pn = new_<DebuggerStatement>(tokenStream.currentToken().pos);
if (!pn)
return NULL;
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->setFunIsHeavyweight();
break;
#if JS_HAS_XML_SUPPORT
@ -4146,7 +4152,7 @@ Parser::statement()
JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NOP);
/* Is this an E4X dagger I see before me? */
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->setFunIsHeavyweight();
ParseNode *pn2 = expr();
if (!pn2)
return NULL;
@ -4535,11 +4541,9 @@ Parser::condExpr1()
* where it's unambiguous, even if we might be parsing the init of a
* for statement.
*/
uint32_t oldflags = tc->sc->flags;
bool oldInForInit = tc->sc->inForInit;
tc->sc->inForInit = false;
ParseNode *thenExpr = assignExpr();
tc->sc->flags = oldflags | (tc->sc->flags & TCF_FUN_FLAGS);
tc->sc->inForInit = oldInForInit;
if (!thenExpr)
return NULL;
@ -4910,7 +4914,7 @@ class GenexpGuard {
TreeContext *tc = parser->tc;
if (tc->parenDepth == 0) {
tc->yieldCount = 0;
tc->yieldNode = tc->argumentsNode = NULL;
tc->yieldNode = NULL;
}
startYieldCount = tc->yieldCount;
tc->parenDepth++;
@ -4961,14 +4965,14 @@ GenexpGuard::maybeNoteGenerator(ParseNode *pn)
{
TreeContext *tc = parser->tc;
if (tc->yieldCount > 0) {
tc->sc->flags |= TCF_FUN_IS_GENERATOR;
tc->sc->setFunIsGenerator();
if (!tc->sc->inFunction) {
parser->reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN_OR_YIELD,
js_yield_str);
return false;
}
if (tc->hasReturnExpr) {
/* At the time we saw the yield, we might not have set TCF_FUN_IS_GENERATOR yet. */
/* At the time we saw the yield, we might not have set funIsGenerator yet. */
ReportBadReturn(tc->sc->context, parser, pn, JSREPORT_ERROR,
JSMSG_BAD_GENERATOR_RETURN,
JSMSG_BAD_ANON_GENERATOR_RETURN);
@ -5464,13 +5468,14 @@ Parser::generatorExpr(ParseNode *kid)
return NULL;
/*
* We assume conservatively that any deoptimization flag in tc->sc->flags
* We assume conservatively that any deoptimization flags in tc->sc
* come from the kid. So we propagate these flags into genfn. For code
* simplicity we also do not detect if the flags were only set in the
* kid and could be removed from tc->sc->flags.
* kid and could be removed from tc->sc.
*/
gensc.flags |= TCF_FUN_IS_GENERATOR | (outertc->sc->flags & TCF_FUN_FLAGS);
funbox->tcflags |= gensc.flags;
gensc.cxFlags = outertc->sc->cxFlags;
gensc.setFunIsGenerator();
funbox->inGenexpLambda = true;
genfn->pn_funbox = funbox;
genfn->pn_blockid = gensc.bodyid;
@ -5641,8 +5646,8 @@ Parser::memberExpr(JSBool allowCallSyntax)
TokenPtr begin = lhs->pn_pos.begin;
if (tt == TOK_LP) {
/* Filters are effectively 'with', so deoptimize names. */
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->noteBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
tc->sc->setBindingsAccessedDynamically();
StmtInfo stmtInfo(context);
ParseNode *oldWith = tc->innermostWith;
@ -5761,14 +5766,14 @@ Parser::memberExpr(JSBool allowCallSyntax)
if (lhs->pn_atom == context->runtime->atomState.evalAtom) {
/* Select JSOP_EVAL and flag tc as heavyweight. */
nextMember->setOp(JSOP_EVAL);
tc->sc->noteBindingsAccessedDynamically();
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->setBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
/*
* In non-strict mode code, direct calls to eval can add
* variables to the call object.
*/
if (!tc->sc->inStrictMode())
tc->sc->noteHasExtensibleScope();
tc->sc->setFunHasExtensibleScope();
}
} else if (lhs->isOp(JSOP_GETPROP)) {
/* Select JSOP_FUNAPPLY given foo.apply(...). */
@ -5809,11 +5814,9 @@ Parser::bracketedExpr()
* where it's unambiguous, even if we might be parsing the init of a
* for statement.
*/
uint32_t oldflags = tc->sc->flags;
bool oldInForInit = tc->sc->inForInit;
tc->sc->inForInit = false;
ParseNode *pn = expr();
tc->sc->flags = oldflags | (tc->sc->flags & TCF_FUN_FLAGS);
tc->sc->inForInit = oldInForInit;
return pn;
}
@ -5919,8 +5922,8 @@ Parser::qualifiedSuffix(ParseNode *pn)
if (!pn2)
return NULL;
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->noteBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
tc->sc->setBindingsAccessedDynamically();
/* Left operand of :: must be evaluated if it is an identifier. */
if (pn->isOp(JSOP_QNAMEPART))
@ -5966,8 +5969,8 @@ Parser::qualifiedIdentifier()
return NULL;
if (tokenStream.matchToken(TOK_DBLCOLON)) {
/* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->noteBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
tc->sc->setBindingsAccessedDynamically();
pn = qualifiedSuffix(pn);
}
return pn;
@ -6471,8 +6474,8 @@ Parser::propertyQualifiedIdentifier()
JS_ASSERT(tokenStream.peekToken() == TOK_DBLCOLON);
/* Deoptimize QualifiedIdentifier properties to avoid tricky analysis. */
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->noteBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
tc->sc->setBindingsAccessedDynamically();
PropertyName *name = tokenStream.currentToken().name();
ParseNode *node = NameNode::create(PNK_NAME, name, this, this->tc->sc);

View File

@ -55,8 +55,6 @@
#include "frontend/ParseNode.h"
#include "frontend/TreeContext.h"
#define NUM_TEMP_FREELISTS 6U /* 32 to 2048 byte size classes (32 bit) */
typedef struct BindData BindData;
namespace js {
@ -70,15 +68,12 @@ enum VarContext { HoistVars, DontHoistVars };
struct Parser : private AutoGCRooter
{
JSContext *const context; /* FIXME Bug 551291: use AutoGCRooter::context? */
void *tempFreeList[NUM_TEMP_FREELISTS];
TokenStream tokenStream;
void *tempPoolMark; /* initial JSContext.tempLifoAlloc mark */
JSPrincipals *principals; /* principals associated with source */
JSPrincipals *originPrincipals; /* see jsapi.h 'originPrincipals' comment */
StackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */
JSObject *const callerVarObj; /* callerFrame's varObj */
ParseNodeAllocator allocator;
uint32_t functionCount; /* number of functions in current unit */
ObjectBox *traceListHead; /* list of parsed object for GC tracing */
TreeContext *tc; /* innermost tree context (stack-allocated) */

View File

@ -52,7 +52,7 @@ using namespace js;
using namespace js::frontend;
static void
FlagHeavyweights(Definition *dn, FunctionBox *funbox, uint32_t *tcflags, bool topInFunction)
FlagHeavyweights(Definition *dn, FunctionBox *funbox, bool *isHeavyweight, bool topInFunction)
{
unsigned dnLevel = dn->frameLevel();
@ -64,17 +64,17 @@ FlagHeavyweights(Definition *dn, FunctionBox *funbox, uint32_t *tcflags, bool to
* funbox whose body contains the dn definition.
*/
if (funbox->level + 1U == dnLevel || (dnLevel == 0 && dn->isLet())) {
funbox->tcflags |= TCF_FUN_HEAVYWEIGHT;
funbox->setFunIsHeavyweight();
break;
}
}
if (!funbox && topInFunction)
*tcflags |= TCF_FUN_HEAVYWEIGHT;
*isHeavyweight = true;
}
static void
SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool topInFunction, bool isDirectEval)
SetFunctionKinds(FunctionBox *funbox, bool *isHeavyweight, bool topInFunction, bool isDirectEval)
{
for (; funbox; funbox = funbox->siblings) {
ParseNode *fn = funbox->node;
@ -86,13 +86,13 @@ SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool topInFunction, boo
continue;
if (funbox->kids)
SetFunctionKinds(funbox->kids, tcflags, topInFunction, isDirectEval);
SetFunctionKinds(funbox->kids, isHeavyweight, topInFunction, isDirectEval);
JSFunction *fun = funbox->function();
JS_ASSERT(fun->kind() == JSFUN_INTERPRETED);
if (funbox->tcflags & TCF_FUN_HEAVYWEIGHT) {
if (funbox->funIsHeavyweight()) {
/* nothing to do */
} else if (isDirectEval || funbox->inAnyDynamicScope()) {
/*
@ -134,7 +134,7 @@ SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool topInFunction, boo
* ensure that its containing function has been flagged as
* heavyweight.
*
* The emitter must see TCF_FUN_HEAVYWEIGHT accurately before
* The emitter must see funIsHeavyweight() accurately before
* generating any code for a tree of nested functions.
*/
AtomDefnMapPtr upvars = pn->pn_names;
@ -144,7 +144,7 @@ SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool topInFunction, boo
Definition *defn = r.front().value();
Definition *lexdep = defn->resolve();
if (!lexdep->isFreeVar())
FlagHeavyweights(lexdep, funbox, tcflags, topInFunction);
FlagHeavyweights(lexdep, funbox, isHeavyweight, topInFunction);
}
}
}
@ -179,7 +179,9 @@ MarkExtensibleScopeDescendants(JSContext *context, FunctionBox *funbox, bool has
if (funbox->kids) {
if (!MarkExtensibleScopeDescendants(context, funbox->kids,
hasExtensibleParent || funbox->scopeIsExtensible())) {
hasExtensibleParent ||
funbox->funHasExtensibleScope()))
{
return false;
}
}
@ -197,6 +199,9 @@ frontend::AnalyzeFunctions(Parser *parser)
if (!MarkExtensibleScopeDescendants(sc->context, sc->functionList, false))
return false;
bool isDirectEval = !!parser->callerFrame;
SetFunctionKinds(sc->functionList, &sc->flags, sc->inFunction, isDirectEval);
bool isHeavyweight = false;
SetFunctionKinds(sc->functionList, &isHeavyweight, sc->inFunction, isDirectEval);
if (isHeavyweight)
sc->setFunIsHeavyweight();
return true;
}

View File

@ -563,7 +563,7 @@ js::ReportStrictModeError(JSContext *cx, TokenStream *ts, SharedContext *sc, Par
/* In strict mode code, this is an error, not merely a warning. */
unsigned flags;
if ((ts && ts->isStrictMode()) || (sc && (sc->flags & TCF_STRICT_MODE_CODE))) {
if ((ts && ts->isStrictMode()) || (sc && sc->inStrictMode())) {
flags = JSREPORT_ERROR;
} else {
if (!cx->hasStrictOption())

View File

@ -51,7 +51,6 @@ namespace js {
inline
SharedContext::SharedContext(JSContext *cx, bool inFunction)
: context(cx),
flags(0),
bodyid(0),
blockidGen(0),
topStmt(NULL),
@ -65,7 +64,8 @@ SharedContext::SharedContext(JSContext *cx, bool inFunction)
bindings(cx),
bindingsRoot(cx, &bindings),
inFunction(inFunction),
inForInit(false)
inForInit(false),
cxFlags(cx)
{
}
@ -103,7 +103,6 @@ TreeContext::TreeContext(Parser *prs, SharedContext *sc)
blockNode(NULL),
decls(prs->context),
yieldNode(NULL),
argumentsNode(NULL),
parserTC(&prs->tc),
lexdeps(prs->context),
parent(prs->tc),
@ -119,8 +118,6 @@ TreeContext::TreeContext(Parser *prs, SharedContext *sc)
inline bool
TreeContext::init(JSContext *cx)
{
if (cx->hasRunOption(JSOPTION_STRICT_MODE))
sc->flags |= TCF_STRICT_MODE_CODE;
return decls.init() && lexdeps.ensureMap(sc->context);
}

View File

@ -56,20 +56,20 @@ typedef struct BindData BindData;
namespace js {
JS_ENUM_HEADER(TreeContextFlags, uint32_t)
{
// function needs Call object per call
TCF_FUN_HEAVYWEIGHT = 0x1,
struct StmtInfo;
// parsed yield statement in function
TCF_FUN_IS_GENERATOR = 0x2,
class ContextFlags {
// This class's data is all private and so only visible to these friends.
friend class SharedContext;
friend class FunctionBox;
// This function/global/eval code body contained a Use Strict Directive.
// Treat certain strict warnings as errors, and forbid the use of 'with'.
// See also TSF_STRICT_MODE_CODE, JSScript::strictModeCode, and
// JSREPORT_STRICT_ERROR.
//
TCF_STRICT_MODE_CODE = 0x4,
bool inStrictMode:1;
// The (static) bindings of this script need to support dynamic name
// read/write access. Here, 'dynamic' means dynamic dictionary lookup on
@ -91,11 +91,22 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t)
// taken not to turn off the whole 'arguments' optimization). To answer the
// more general "is this argument aliased" question, script->needsArgsObj
// should be tested (see JSScript::argIsAlised).
TCF_BINDINGS_ACCESSED_DYNAMICALLY = 0x8,
//
bool bindingsAccessedDynamically:1;
// The |fun*| flags are only relevant if |inFunction| is true. Due to
// sloppiness, however, some are set in cases where |inFunction| is
// false.
// The function needs Call object per call.
bool funIsHeavyweight:1;
// We parsed a yield statement in the function.
bool funIsGenerator:1;
// The function or a function that encloses it may define new local names
// at runtime through means other than calling eval.
TCF_FUN_MIGHT_ALIAS_LOCALS = 0x10,
bool funMightAliasLocals:1;
// This function does something that can extend the set of bindings in its
// call objects --- it does a direct eval in non-strict code, or includes a
@ -104,7 +115,7 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t)
// This flag is *not* inherited by enclosed or enclosing functions; it
// applies only to the function in whose flags it appears.
//
TCF_FUN_EXTENSIBLE_SCOPE = 0x20,
bool funHasExtensibleScope:1;
// Technically, every function has a binding named 'arguments'. Internally,
// this binding is only added when 'arguments' is mentioned by the function
@ -127,7 +138,7 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t)
// have no special semantics: the initial value is unconditionally the
// actual argument (or undefined if nactual < nformal).
//
TCF_ARGUMENTS_HAS_LOCAL_BINDING = 0x40,
bool funArgumentsHasLocalBinding:1;
// In many cases where 'arguments' has a local binding (as described above)
// we do not need to actually create an arguments object in the function
@ -138,27 +149,24 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t)
// be unsound in several cases. The frontend filters out such cases by
// setting this flag which eagerly sets script->needsArgsObj to true.
//
TCF_DEFINITELY_NEEDS_ARGS_OBJ = 0x80
bool funDefinitelyNeedsArgsObj:1;
} JS_ENUM_FOOTER(TreeContextFlags);
// Sticky deoptimization flags to propagate from FunctionBody.
static const uint32_t TCF_FUN_FLAGS = TCF_FUN_HEAVYWEIGHT |
TCF_FUN_IS_GENERATOR |
TCF_BINDINGS_ACCESSED_DYNAMICALLY |
TCF_FUN_MIGHT_ALIAS_LOCALS |
TCF_STRICT_MODE_CODE |
TCF_FUN_EXTENSIBLE_SCOPE |
TCF_ARGUMENTS_HAS_LOCAL_BINDING |
TCF_DEFINITELY_NEEDS_ARGS_OBJ;
struct StmtInfo;
public:
ContextFlags(JSContext *cx)
: inStrictMode(cx->hasRunOption(JSOPTION_STRICT_MODE)),
bindingsAccessedDynamically(false),
funIsHeavyweight(false),
funIsGenerator(false),
funMightAliasLocals(false),
funHasExtensibleScope(false),
funArgumentsHasLocalBinding(false),
funDefinitelyNeedsArgsObj(false)
{ }
};
struct SharedContext {
JSContext *context;
uint32_t flags; /* statement state flags, see above */
uint32_t bodyid; /* block number of program/function body */
uint32_t blockidGen; /* preincremented block number generator */
@ -190,21 +198,28 @@ struct SharedContext {
bool inForInit:1; /* parsing/emitting init expr of for; exclude 'in' */
ContextFlags cxFlags;
inline SharedContext(JSContext *cx, bool inFunction);
bool inStrictMode() const { return flags & TCF_STRICT_MODE_CODE; }
bool bindingsAccessedDynamically() const { return flags & TCF_BINDINGS_ACCESSED_DYNAMICALLY; }
bool mightAliasLocals() const { return flags & TCF_FUN_MIGHT_ALIAS_LOCALS; }
bool hasExtensibleScope() const { return flags & TCF_FUN_EXTENSIBLE_SCOPE; }
bool argumentsHasLocalBinding() const { return flags & TCF_ARGUMENTS_HAS_LOCAL_BINDING; }
bool definitelyNeedsArgsObj() const { return flags & TCF_DEFINITELY_NEEDS_ARGS_OBJ; }
bool inStrictMode() const { return cxFlags.inStrictMode; }
bool bindingsAccessedDynamically() const { return cxFlags.bindingsAccessedDynamically; }
bool funIsHeavyweight() const { return cxFlags.funIsHeavyweight; }
bool funIsGenerator() const { return cxFlags.funIsGenerator; }
bool funMightAliasLocals() const { return cxFlags.funMightAliasLocals; }
bool funHasExtensibleScope() const { return cxFlags.funHasExtensibleScope; }
bool funArgumentsHasLocalBinding() const { return cxFlags.funArgumentsHasLocalBinding; }
bool funDefinitelyNeedsArgsObj() const { return cxFlags.funDefinitelyNeedsArgsObj; }
void noteMightAliasLocals() { flags |= TCF_FUN_MIGHT_ALIAS_LOCALS; }
void noteBindingsAccessedDynamically() { flags |= TCF_BINDINGS_ACCESSED_DYNAMICALLY; }
void noteHasExtensibleScope() { flags |= TCF_FUN_EXTENSIBLE_SCOPE; }
void noteArgumentsHasLocalBinding() { flags |= TCF_ARGUMENTS_HAS_LOCAL_BINDING; }
void noteDefinitelyNeedsArgsObj() { JS_ASSERT(argumentsHasLocalBinding());
flags |= TCF_DEFINITELY_NEEDS_ARGS_OBJ; }
void setInStrictMode() { cxFlags.inStrictMode = true; }
void setBindingsAccessedDynamically() { cxFlags.bindingsAccessedDynamically = true; }
void setFunIsHeavyweight() { cxFlags.funIsHeavyweight = true; }
void setFunIsGenerator() { cxFlags.funIsGenerator = true; }
void setFunMightAliasLocals() { cxFlags.funMightAliasLocals = true; }
void setFunHasExtensibleScope() { cxFlags.funHasExtensibleScope = true; }
void setFunArgumentsHasLocalBinding() { cxFlags.funArgumentsHasLocalBinding = true; }
void setFunDefinitelyNeedsArgsObj() { JS_ASSERT(cxFlags.funArgumentsHasLocalBinding);
cxFlags.funDefinitelyNeedsArgsObj = true; }
unsigned argumentsLocalSlot() const;
@ -257,9 +272,6 @@ struct TreeContext { /* tree context for semantic checks */
ParseNode *yieldNode; /* parse node for a yield expression that might
be an error if we turn out to be inside a
generator expression */
ParseNode *argumentsNode; /* parse node for an arguments variable that
might be an error if we turn out to be
inside a generator expression */
private:
TreeContext **parserTC; /* this points to the Parser's active tc

View File

@ -0,0 +1,40 @@
// |jit-test| error: TypeError;
function printStatus (msg) {}
function toPrinted(value) {
value = value.replace(/\\n/g, 'NL')
}
function reportCompare (expected, actual, description) {
printStatus ("Expected value '" + toPrinted(expected) + "' matched actual value '" + toPrinted(actual) + "'");
}
var UBound = 0;
var statusitems = [];
var actual = '';
var actualvalues = [];
var expect= '';
var expectedvalues = [];
testThis('x()');
testThis('"abc"()');
testThis('x()');
testThis('Date(12345)()');
testThis('x()');
testThis('1()');
testThis('x()');
testThis('void(0)()');
testThis('x()');
testThis('[1,2,3,4,5](1)');
gczeal(4);
testThis('x(1)');
checkThis('(function (y) {return y+1;})("abc")');
checkThis('f("abc")');
function testThis(sInvalidSyntax) {
expectedvalues[UBound] = expect;
actualvalues[UBound] = actual;
UBound++;
}
function checkThis(sValidSyntax) {
for (var i=0; i<UBound; i++)
reportCompare(expectedvalues[i], actualvalues[i], statusitems[i]);
}
var actualvalues = [];
for (var i=0; i<UBound; i++)
reportCompare(expectedvalues[i], actualvalues[i], statusitems[i]);

View File

@ -484,18 +484,6 @@ js_DumpAtoms(JSContext *cx, FILE *fp)
}
#endif
#if JS_BITS_PER_WORD == 32
# define TEMP_SIZE_START_LOG2 5
#else
# define TEMP_SIZE_START_LOG2 6
#endif
#define TEMP_SIZE_LIMIT_LOG2 (TEMP_SIZE_START_LOG2 + NUM_TEMP_FREELISTS)
#define TEMP_SIZE_START JS_BIT(TEMP_SIZE_START_LOG2)
#define TEMP_SIZE_LIMIT JS_BIT(TEMP_SIZE_LIMIT_LOG2)
JS_STATIC_ASSERT(TEMP_SIZE_START >= sizeof(JSHashTable));
namespace js {
void

View File

@ -395,7 +395,8 @@ Valueify(const JSClass *c)
* value of objects.
*/
enum ESClassValue {
ESClass_Array, ESClass_Number, ESClass_String, ESClass_Boolean, ESClass_RegExp
ESClass_Array, ESClass_Number, ESClass_String, ESClass_Boolean,
ESClass_RegExp, ESClass_ArrayBuffer
};
/*

View File

@ -81,6 +81,7 @@
# include "methodjit/MethodJIT.h"
#endif
#include "gc/Marking.h"
#include "js/MemoryMetrics.h"
#include "frontend/TokenStream.h"
#include "frontend/ParseMaps.h"
#include "yarr/BumpPointerAllocator.h"
@ -93,27 +94,65 @@
using namespace js;
using namespace js::gc;
void
JSRuntime::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, size_t *temporary,
size_t *mjitCode, size_t *regexpCode, size_t *unusedCodeMemory,
size_t *stackCommitted, size_t *gcMarkerSize)
struct CallbackData
{
if (normal)
*normal = mallocSizeOf(dtoaState);
CallbackData(JSMallocSizeOfFun f) : mallocSizeOf(f), n(0) {}
JSMallocSizeOfFun mallocSizeOf;
size_t n;
};
if (temporary)
*temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
void CompartmentCallback(JSRuntime *rt, void *vdata, JSCompartment *compartment)
{
CallbackData *data = (CallbackData *) vdata;
data->n += data->mallocSizeOf(compartment);
}
void
JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, RuntimeSizes *runtime)
{
runtime->object = mallocSizeOf(this);
runtime->atomsTable = atomState.atoms.sizeOfExcludingThis(mallocSizeOf);
runtime->contexts = 0;
for (ContextIter acx(this); !acx.done(); acx.next())
runtime->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
runtime->dtoa = mallocSizeOf(dtoaState);
runtime->temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
if (execAlloc_)
execAlloc_->sizeOfCode(mjitCode, regexpCode, unusedCodeMemory);
execAlloc_->sizeOfCode(&runtime->mjitCode, &runtime->regexpCode,
&runtime->unusedCodeMemory);
else
*mjitCode = *regexpCode = *unusedCodeMemory = 0;
runtime->mjitCode = runtime->regexpCode = runtime->unusedCodeMemory = 0;
if (stackCommitted)
*stackCommitted = stackSpace.sizeOfCommitted();
runtime->stackCommitted = stackSpace.sizeOfCommitted();
if (gcMarkerSize)
*gcMarkerSize = gcMarker.sizeOfExcludingThis(mallocSizeOf);
runtime->gcMarker = gcMarker.sizeOfExcludingThis(mallocSizeOf);
runtime->mathCache = mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
runtime->scriptFilenames = scriptFilenameTable.sizeOfExcludingThis(mallocSizeOf);
for (ScriptFilenameTable::Range r = scriptFilenameTable.all(); !r.empty(); r.popFront())
runtime->scriptFilenames += mallocSizeOf(r.front());
runtime->compartmentObjects = 0;
CallbackData data(mallocSizeOf);
JS_IterateCompartments(this, &data, CompartmentCallback);
runtime->compartmentObjects = data.n;
}
size_t
JSRuntime::sizeOfExplicitNonHeap()
{
if (!execAlloc_)
return 0;
size_t mjitCode, regexpCode, unusedCodeMemory;
execAlloc_->sizeOfCode(&mjitCode, &regexpCode, &unusedCodeMemory);
return mjitCode + regexpCode + unusedCodeMemory + stackSpace.sizeOfCommitted();
}
void

View File

@ -376,6 +376,10 @@ class FreeOp : public JSFreeOp {
} /* namespace js */
namespace JS {
struct RuntimeSizes;
}
struct JSRuntime : js::RuntimeFriendFields
{
/* Default compartment. */
@ -880,9 +884,8 @@ struct JSRuntime : js::RuntimeFriendFields
return jitHardening;
}
void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, size_t *temporary,
size_t *mjitCode, size_t *regexpCode, size_t *unusedCodeMemory,
size_t *stackCommitted, size_t *gcMarker);
void sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, js::RuntimeSizes *runtime);
size_t sizeOfExplicitNonHeap();
};
/* Common macros to access thread-local caches in JSRuntime. */

View File

@ -1201,30 +1201,6 @@ IsBuiltinFunctionConstructor(JSFunction *fun)
return fun->maybeNative() == Function;
}
const Shape *
LookupInterpretedFunctionPrototype(JSContext *cx, RootedVarObject funobj)
{
#ifdef DEBUG
JSFunction *fun = funobj->toFunction();
JS_ASSERT(fun->isInterpreted());
JS_ASSERT(!fun->isFunctionPrototype());
JS_ASSERT(!funobj->isBoundFunction());
#endif
jsid id = NameToId(cx->runtime->atomState.classPrototypeAtom);
RootedVar<const Shape*> shape(cx, funobj->nativeLookup(cx, id));
if (!shape) {
if (!ResolveInterpretedFunctionPrototype(cx, funobj))
return NULL;
id = NameToId(cx->runtime->atomState.classPrototypeAtom);
shape = funobj->nativeLookup(cx, id);
}
JS_ASSERT(!shape->configurable());
JS_ASSERT(shape->isDataDescriptor());
JS_ASSERT(shape->hasSlot());
return shape;
}
} /* namespace js */
JSFunction *

View File

@ -107,6 +107,12 @@ MathCache::MathCache() {
JS_ASSERT(hash(-0.0) != hash(+0.0));
}
size_t
MathCache::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf)
{
return mallocSizeOf(this);
}
Class js::MathClass = {
js_Math_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Math),

View File

@ -74,6 +74,8 @@ class MathCache
e.f = f;
return (e.out = f(x));
}
size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf);
};
} /* namespace js */

View File

@ -1595,6 +1595,7 @@ ObjectClassIs(JSObject &obj, ESClassValue classValue, JSContext *cx)
case ESClass_String: return obj.isString();
case ESClass_Boolean: return obj.isBoolean();
case ESClass_RegExp: return obj.isRegExp();
case ESClass_ArrayBuffer: return obj.isArrayBuffer();
}
JS_NOT_REACHED("bad classValue");
return false;

View File

@ -2950,7 +2950,7 @@ ASTSerializer::function(ParseNode *pn, ASTType type, Value *dst)
bool isGenerator =
#if JS_HAS_GENERATORS
pn->pn_funbox->tcflags & TCF_FUN_IS_GENERATOR;
pn->pn_funbox->funIsGenerator();
#else
false;
#endif

View File

@ -1329,24 +1329,28 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
bce->regexpList.finish(script->regexps());
if (bce->constList.length() != 0)
bce->constList.finish(script->consts());
if (bce->sc->flags & TCF_STRICT_MODE_CODE)
script->strictModeCode = true;
script->strictModeCode = bce->sc->inStrictMode();
if (bce->parser->compileAndGo) {
script->compileAndGo = true;
const StackFrame *fp = bce->parser->callerFrame;
if (fp && fp->isFunctionFrame())
script->savedCallerFun = true;
}
if (bce->sc->bindingsAccessedDynamically())
script->bindingsAccessedDynamically = true;
script->bindingsAccessedDynamically = bce->sc->bindingsAccessedDynamically();
script->hasSingletons = bce->hasSingletons;
if (bce->sc->flags & TCF_FUN_IS_GENERATOR)
script->isGenerator = true;
if (bce->sc->argumentsHasLocalBinding()) {
script->setArgumentsHasLocalBinding(bce->sc->argumentsLocalSlot());
if (bce->sc->definitelyNeedsArgsObj())
script->setNeedsArgsObj(true);
if (bce->sc->inFunction) {
if (bce->sc->funArgumentsHasLocalBinding()) {
// This must precede the script->bindings.transfer() call below.
script->setArgumentsHasLocalBinding(bce->sc->argumentsLocalSlot());
if (bce->sc->funDefinitelyNeedsArgsObj())
script->setNeedsArgsObj(true);
} else {
JS_ASSERT(!bce->sc->funDefinitelyNeedsArgsObj());
}
} else {
JS_ASSERT(!bce->sc->funArgumentsHasLocalBinding());
JS_ASSERT(!bce->sc->funDefinitelyNeedsArgsObj());
}
if (nClosedArgs)
@ -1360,6 +1364,9 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
if (bce->sc->inFunction) {
JS_ASSERT(!bce->noScriptRval);
JS_ASSERT(!bce->needScriptGlobal);
script->isGenerator = bce->sc->funIsGenerator();
/*
* We initialize fun->script() to be the script constructed above
* so that the debugger has a valid fun->script().
@ -1367,7 +1374,7 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
fun = bce->sc->fun();
JS_ASSERT(fun->isInterpreted());
JS_ASSERT(!fun->script());
if (bce->sc->flags & TCF_FUN_HEAVYWEIGHT)
if (bce->sc->funIsHeavyweight())
fun->flags |= JSFUN_HEAVYWEIGHT;
/*
@ -1383,7 +1390,12 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
fun->setScript(script);
script->globalObject = fun->getParent() ? &fun->getParent()->global() : NULL;
} else {
// It'd be nice to JS_ASSERT(!bce->sc->funIsHeavyweight()) here, but
// Parser.cpp is sloppy and sometimes applies it to non-functions.
JS_ASSERT(!bce->sc->funIsGenerator());
/*
* Initialize script->object, if necessary, so that the debugger has a
* valid holder object.

View File

@ -529,7 +529,7 @@ struct JSScript : public js::gc::Cell
bool savedCallerFun:1; /* can call getCallerFunction() */
bool strictModeCode:1; /* code is in strict mode */
bool compileAndGo:1; /* see Parser::compileAndGo */
bool bindingsAccessedDynamically:1; /* see TCF_BINDINGS_ACCESSED_DYNAMICALLY */
bool bindingsAccessedDynamically:1; /* see ContextFlags' field of the same name */
bool warnedAboutTwoArgumentEval:1; /* have warned about use of
obsolete eval(s, o) in
this script */
@ -589,7 +589,7 @@ struct JSScript : public js::gc::Cell
void setVersion(JSVersion v) { version = v; }
/* See TCF_ARGUMENTS_HAS_LOCAL_BINDING comment. */
/* See ContextFlags::funArgumentsHasLocalBinding comment. */
bool argumentsHasLocalBinding() const { return argsHasLocalBinding_; }
jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; }
unsigned argumentsLocalSlot() const { JS_ASSERT(argsHasLocalBinding_); return argsSlot_; }

View File

@ -785,6 +785,22 @@ ArrayBufferObject::obj_typeOf(JSContext *cx, JSObject *obj)
return JSTYPE_OBJECT;
}
/*
* ArrayBufferViews of various sorts
*/
static JSObject *
GetProtoForClass(JSContext *cx, Class *clasp)
{
// Pass in the proto from this compartment
GlobalObject *parent = GetCurrentGlobal(cx);
Root<GlobalObject*> parentRoot(cx, &parent);
JSObject *proto;
if (!FindProto(cx, clasp, parentRoot, &proto))
return NULL;
return proto;
}
/*
* TypedArray
*
@ -1068,12 +1084,6 @@ template<typename NativeType>
class TypedArrayTemplate
: public TypedArray
{
template<typename ElementType>
friend JSObject *NewTypedArrayFromArray(JSContext *cx, JSObject *other);
template<typename ElementType>
friend JSObject *NewArray(JSContext *cx, uint32_t nelements);
public:
typedef NativeType ThisType;
typedef TypedArrayTemplate<NativeType> ThisTypeArray;
@ -1440,7 +1450,8 @@ class TypedArrayTemplate
}
static JSObject *
createTypedArray(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len)
makeInstance(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len,
HandleObject proto)
{
RootedVarObject obj(cx, NewBuiltinClassInstance(cx, protoClass()));
if (!obj)
@ -1451,14 +1462,19 @@ class TypedArrayTemplate
JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT8);
#endif
/*
* Specialize the type of the object on the current scripted location,
* and mark the type as definitely a typed array.
*/
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(protoClass());
types::TypeObject *type = types::GetTypeCallerInitObject(cx, key);
if (!type)
return NULL;
types::TypeObject *type;
if (proto) {
type = proto->getNewType(cx);
} else {
/*
* Specialize the type of the object on the current scripted location,
* and mark the type as definitely a typed array.
*/
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(protoClass());
type = types::GetTypeCallerInitObject(cx, key);
if (!type)
return NULL;
}
obj->setType(type);
obj->setSlot(FIELD_TYPE, Int32Value(ArrayTypeID()));
@ -1516,6 +1532,18 @@ class TypedArrayTemplate
return true;
}
static JSBool
fromBuffer(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSObject *obj = fromBuffer(cx, RootedVarObject(cx, &args[0].toObject()),
args[1].toInt32(), args[2].toInt32(), RootedVarObject(cx, &args[3].toObject()));
if (!obj)
return false;
vp->setObject(*obj);
return true;
}
static JSObject *
create(JSContext *cx, unsigned argc, Value *argv)
{
@ -1523,40 +1551,29 @@ class TypedArrayTemplate
/* () or (number) */
uint32_t len = 0;
if (argc == 0 || ValueIsLength(cx, argv[0], &len)) {
RootedVarObject bufobj(cx, createBufferWithSizeAndCount(cx, len));
if (!bufobj)
return NULL;
return createTypedArray(cx, bufobj, 0, len);
}
if (argc == 0 || ValueIsLength(cx, argv[0], &len))
return fromLength(cx, len);
/* (not an object) */
if (!argv[0].isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_TYPED_ARRAY_BAD_ARGS);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return NULL;
}
RootedVarObject dataObj(cx, &argv[0].toObject());
/* (typedArray) */
if (dataObj->isTypedArray()) {
JSObject *otherTypedArray = getTypedArray(dataObj);
JS_ASSERT(otherTypedArray);
/*
* (typedArray)
* (type[] array)
*
* Otherwise create a new typed array and copy elements 0..len-1
* properties from the object, treating it as some sort of array.
* Note that offset and length will be ignored
*/
if (!UnwrapObject(dataObj)->isArrayBuffer())
return fromArray(cx, dataObj);
uint32_t len = getLength(otherTypedArray);
RootedVarObject bufobj(cx, createBufferWithSizeAndCount(cx, len));
if (!bufobj)
return NULL;
JSObject *obj = createTypedArray(cx, bufobj, 0, len);
if (!obj || !copyFromTypedArray(cx, obj, otherTypedArray, 0))
return NULL;
return obj;
}
/* (obj, byteOffset, length). */
/* (ArrayBuffer, [byteOffset, [length]]) */
int32_t byteOffset = -1;
int32_t length = -1;
@ -1580,8 +1597,7 @@ class TypedArrayTemplate
}
}
/* (obj, byteOffset, length) */
return createTypedArrayWithOffsetLength(cx, dataObj, byteOffset, length);
return fromBuffer(cx, dataObj, byteOffset, length, RootedVarObject(cx));
}
/* subarray(start[, end]) */
@ -1693,9 +1709,61 @@ class TypedArrayTemplate
public:
static JSObject *
createTypedArrayWithBuffer(JSContext *cx, HandleObject bufobj,
int32_t byteOffsetInt, int32_t lengthInt)
fromBuffer(JSContext *cx, HandleObject bufobj, int32_t byteOffsetInt, int32_t lengthInt,
HandleObject proto)
{
if (!ObjectClassIs(*bufobj, ESClass_ArrayBuffer, cx)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return NULL; // must be arrayBuffer
}
JS_ASSERT(bufobj->isArrayBuffer() || bufobj->isProxy());
if (bufobj->isProxy()) {
/*
* Normally, NonGenericMethodGuard handles the case of transparent
* wrappers. However, we have a peculiar situation: we want to
* construct the new typed array in the compartment of the buffer,
* so that the typed array can point directly at their buffer's
* data without crossing compartment boundaries. So we use the
* machinery underlying NonGenericMethodGuard directly to proxy the
* native call. We will end up with a wrapper in the origin
* compartment for a view in the target compartment referencing the
* ArrayBuffer in that same compartment.
*/
JSObject *wrapped = UnwrapObjectChecked(cx, bufobj);
if (!wrapped)
return NULL;
if (wrapped->isArrayBuffer()) {
/*
* And for even more fun, the new view's prototype should be
* set to the origin compartment's prototype object, not the
* target's (specifically, the actual view in the target
* compartment will use as its prototype a wrapper around the
* origin compartment's view.prototype object)
*/
JSObject *proto = GetProtoForClass(cx, fastClass());
if (!proto)
return NULL;
Value argv[] = { UndefinedValue(),
MagicValue(JS_IS_CONSTRUCTING),
ObjectValue(*bufobj),
Int32Value(byteOffsetInt),
Int32Value(lengthInt),
ObjectValue(*proto) };
uint32_t argc = sizeof(argv) / sizeof(argv[0]) - 2;
CallArgs args = CallArgsFromVp(argc, argv);
if (!Proxy::nativeCall(cx, bufobj, &ArrayBufferClass, fromBuffer, args))
return NULL;
return &args.rval().toObject();
}
}
if (!bufobj->isArrayBuffer()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return NULL; // must be arrayBuffer
}
uint32_t boffset = (byteOffsetInt == -1) ? 0 : uint32_t(byteOffsetInt);
ArrayBufferObject &buffer = bufobj->asArrayBuffer();
@ -1728,11 +1796,20 @@ class TypedArrayTemplate
return NULL; // boffset + len is too big for the arraybuffer
}
return createTypedArray(cx, bufobj, boffset, len);
return makeInstance(cx, bufobj, boffset, len, proto);
}
static JSObject *
createTypedArrayFromArray(JSContext *cx, HandleObject other)
fromLength(JSContext *cx, int32_t nelements)
{
RootedVarObject buffer(cx, createBufferWithSizeAndCount(cx, nelements));
if (!buffer)
return NULL;
return makeInstance(cx, buffer, 0, nelements, RootedVarObject(cx, NULL));
}
static JSObject *
fromArray(JSContext *cx, HandleObject other)
{
uint32_t len;
if (!js_GetLengthProperty(cx, other, &len))
@ -1742,33 +1819,12 @@ class TypedArrayTemplate
if (!bufobj)
return NULL;
RootedVarObject obj(cx, createTypedArray(cx, bufobj, 0, len));
RootedVarObject obj(cx, makeInstance(cx, bufobj, 0, len, RootedVarObject(cx)));
if (!obj || !copyFromArray(cx, obj, other, len))
return NULL;
return obj;
}
/*
* Note: the offset and length arguments are ignored if an array is passed in.
*/
static JSObject *
createTypedArrayWithOffsetLength(JSContext *cx, HandleObject other,
int32_t byteOffsetInt, int32_t lengthInt)
{
JS_ASSERT(!other->isTypedArray());
if (other->isArrayBuffer()) {
/* Handle creation from an ArrayBuffer not ArrayBuffer.prototype. */
return createTypedArrayWithBuffer(cx, other, byteOffsetInt, lengthInt);
}
/*
* Otherwise create a new typed array and copy len properties from
* the object.
*/
return createTypedArrayFromArray(cx, other);
}
static const NativeType
getIndex(JSObject *obj, uint32_t index)
{
@ -1801,7 +1857,7 @@ class TypedArrayTemplate
JS_ASSERT(UINT32_MAX - begin * sizeof(NativeType) >= getByteOffset(tarray));
uint32_t byteOffset = getByteOffset(tarray) + begin * sizeof(NativeType);
return createTypedArray(cx, bufobj, byteOffset, length);
return makeInstance(cx, bufobj, byteOffset, length, RootedVarObject(cx));
}
protected:
@ -2172,14 +2228,8 @@ TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, JSObject *tarray, ui
}
JSBool
DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
DataViewObject::construct(JSContext *cx, JSObject *bufobj, const CallArgs &args, JSObject *proto)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSObject *bufobj;
if (!GetFirstArgumentAsObject(cx, args.length(), args.base(), "DataView constructor", &bufobj))
return false;
if (!bufobj->isArrayBuffer()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_EXPECTED_TYPE,
"DataView", "ArrayBuffer", bufobj->getClass()->name);
@ -2227,7 +2277,7 @@ DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
return false;
}
JSObject *obj = DataViewObject::create(cx, byteOffset, byteLength, buffer);
JSObject *obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
if (!obj)
return false;
args.rval().setObject(*obj);
@ -2264,6 +2314,51 @@ DataViewObject::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value
return true;
}
JSBool
DataViewObject::constructWithProto(JSContext *cx, unsigned argc, Value *vp)
{
// Pop the proto argument off the end
CallArgs args = CallArgsFromVp(argc, vp);
JSObject &proto = args[args.length() - 1].toObject();
// And now mimic class_constructor for everything else, but pass in the proto
args = CallArgsFromVp(argc - 1, vp);
JSObject *bufobj;
if (!GetFirstArgumentAsObject(cx, args.length(), args.base(), "DataView constructor", &bufobj))
return false;
return construct(cx, bufobj, args, &proto);
}
JSBool
DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSObject *bufobj;
if (!GetFirstArgumentAsObject(cx, args.length(), args.base(), "DataView constructor", &bufobj))
return false;
if (bufobj->isWrapper() && UnwrapObject(bufobj)->isArrayBuffer()) {
JSObject *proto = GetProtoForClass(cx, &DataViewClass);
if (!proto)
return false;
Vector<Value, 6> argv(cx);
argv.resize(argc + 2 + 1);
memcpy(argv.begin(), args.base(), sizeof(Value) * (argc + 2));
argv[argc + 2].setObject(*proto);
argv[0].setUndefined(); // We want to use a different callee (avoid an assertion)
CallArgs proxyArgs = CallArgsFromVp(argc + 1, argv.begin());
if (!Proxy::nativeCall(cx, bufobj, &DataViewClass, constructWithProto, proxyArgs))
return false;
args.rval() = proxyArgs.rval();
return true;
}
return construct(cx, bufobj, args, NULL);
}
JSBool
DataViewObject::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
@ -2831,48 +2926,26 @@ JSFunctionSpec _typedArray::jsfuncs[] = { \
JS_FS_END \
}
template<typename ElementType>
static inline JSObject *
NewArray(JSContext *cx, uint32_t nelements)
{
RootedVarObject buffer(cx, TypedArrayTemplate<ElementType>::createBufferWithSizeAndCount(cx, nelements));
if (!buffer)
return NULL;
return TypedArrayTemplate<ElementType>::createTypedArray(cx, buffer, 0, nelements);
}
template<typename ElementType>
static inline JSObject *
NewArrayWithBuffer(JSContext *cx, HandleObject arrayBuffer, int32_t byteoffset, int32_t intLength)
{
if (!arrayBuffer->isArrayBuffer()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
return NULL; // must be arrayBuffer
}
return TypedArrayTemplate<ElementType>::createTypedArrayWithBuffer(cx, arrayBuffer,
byteoffset, intLength);
}
#define IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Name,NativeType) \
JS_FRIEND_API(JSObject *) JS_New ## Name ## Array(JSContext *cx, uint32_t nelements) \
{ \
MOZ_ASSERT(nelements <= INT32_MAX); \
return NewArray<NativeType>(cx, nelements); \
return TypedArrayTemplate<NativeType>::fromLength(cx, nelements); \
} \
JS_FRIEND_API(JSObject *) JS_New ## Name ## ArrayFromArray(JSContext *cx, JSObject *other) \
{ \
return TypedArrayTemplate<NativeType>::createTypedArrayFromArray(cx, RootedVarObject(cx, other)); \
return TypedArrayTemplate<NativeType>::fromArray(cx, RootedVarObject(cx, other)); \
} \
JS_FRIEND_API(JSObject *) JS_New ## Name ## ArrayWithBuffer(JSContext *cx, \
JSObject *arrayBuffer, uint32_t byteoffset, int32_t length) \
{ \
MOZ_ASSERT(byteoffset <= INT32_MAX); \
return NewArrayWithBuffer<NativeType>(cx, RootedVarObject(cx, arrayBuffer), byteoffset, length); \
return TypedArrayTemplate<NativeType>::fromBuffer(cx, RootedVarObject(cx, arrayBuffer), byteoffset, length, RootedVarObject(cx)); \
} \
JS_FRIEND_API(JSBool) JS_Is ## Name ## Array(JSObject *obj, JSContext *cx) \
{ \
obj = UnwrapObject(obj); \
if (!(obj = UnwrapObjectChecked(cx, obj))) \
return false; \
Class *clasp = obj->getClass(); \
return (clasp == &TypedArray::classes[TypedArrayTemplate<NativeType>::ArrayTypeID()]); \
}
@ -3192,38 +3265,66 @@ js_InitTypedArrayClasses(JSContext *cx, JSObject *obj)
/* JS Friend API */
// The typed array friend API defines a number of accessor functions that want
// to unwrap an argument, but in certain rare cases may not have a cx available
// and so pass in NULL instead. Use UnwrapObjectChecked when possible.
static JSObject *
CheckedUnwrap(JSContext *cx, JSObject *obj)
{
if (!cx)
return UnwrapObject(obj);
MOZ_ASSERT(!cx->isExceptionPending());
obj = UnwrapObjectChecked(cx, obj);
MOZ_ASSERT(obj);
return obj;
}
JS_FRIEND_API(JSBool)
JS_IsArrayBufferObject(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
MOZ_ASSERT(!cx->isExceptionPending());
if (!(obj = UnwrapObjectChecked(cx, obj))) {
cx->clearPendingException();
return false;
}
return obj->isArrayBuffer();
}
JS_FRIEND_API(JSBool)
JS_IsTypedArrayObject(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
MOZ_ASSERT(!cx->isExceptionPending());
if (!(obj = UnwrapObjectChecked(cx, obj))) {
cx->clearPendingException();
return false;
}
return obj->isTypedArray();
}
JS_FRIEND_API(JSBool)
JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
MOZ_ASSERT(!cx->isExceptionPending());
if (!(obj = UnwrapObjectChecked(cx, obj))) {
cx->clearPendingException();
return false;
}
return obj->isTypedArray() || obj->isDataView();
}
JS_FRIEND_API(uint32_t)
JS_GetArrayBufferByteLength(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return 0;
return obj->asArrayBuffer().byteLength();
}
JS_FRIEND_API(uint8_t *)
JS_GetArrayBufferData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
return obj->asArrayBuffer().dataPointer();
}
@ -3237,7 +3338,8 @@ JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
JS_FRIEND_API(uint32_t)
JS_GetTypedArrayLength(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return 0;
JS_ASSERT(obj->isTypedArray());
return obj->getSlot(TypedArray::FIELD_LENGTH).toInt32();
}
@ -3245,7 +3347,8 @@ JS_GetTypedArrayLength(JSObject *obj, JSContext *cx)
JS_FRIEND_API(uint32_t)
JS_GetTypedArrayByteOffset(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return 0;
JS_ASSERT(obj->isTypedArray());
return obj->getSlot(TypedArray::FIELD_BYTEOFFSET).toInt32();
}
@ -3253,7 +3356,8 @@ JS_GetTypedArrayByteOffset(JSObject *obj, JSContext *cx)
JS_FRIEND_API(uint32_t)
JS_GetTypedArrayByteLength(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return 0;
JS_ASSERT(obj->isTypedArray());
return obj->getSlot(TypedArray::FIELD_BYTELENGTH).toInt32();
}
@ -3261,7 +3365,8 @@ JS_GetTypedArrayByteLength(JSObject *obj, JSContext *cx)
JS_FRIEND_API(JSArrayBufferViewType)
JS_GetTypedArrayType(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return ArrayBufferView::TYPE_MAX;
JS_ASSERT(obj->isTypedArray());
return static_cast<JSArrayBufferViewType>(obj->getSlot(TypedArray::FIELD_TYPE).toInt32());
}
@ -3269,7 +3374,8 @@ JS_GetTypedArrayType(JSObject *obj, JSContext *cx)
JS_FRIEND_API(int8_t *)
JS_GetInt8ArrayData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isTypedArray());
JS_ASSERT(obj->getSlot(TypedArray::FIELD_TYPE).toInt32() == ArrayBufferView::TYPE_INT8);
return static_cast<int8_t *>(TypedArray::getDataOffset(obj));
@ -3278,7 +3384,8 @@ JS_GetInt8ArrayData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(uint8_t *)
JS_GetUint8ArrayData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isTypedArray());
JS_ASSERT(obj->getSlot(TypedArray::FIELD_TYPE).toInt32() == ArrayBufferView::TYPE_UINT8);
return static_cast<uint8_t *>(TypedArray::getDataOffset(obj));
@ -3287,7 +3394,8 @@ JS_GetUint8ArrayData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(uint8_t *)
JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isTypedArray());
JS_ASSERT(obj->getSlot(TypedArray::FIELD_TYPE).toInt32() == ArrayBufferView::TYPE_UINT8_CLAMPED);
return static_cast<uint8_t *>(TypedArray::getDataOffset(obj));
@ -3296,7 +3404,8 @@ JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(int16_t *)
JS_GetInt16ArrayData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isTypedArray());
JS_ASSERT(obj->getSlot(TypedArray::FIELD_TYPE).toInt32() == ArrayBufferView::TYPE_INT16);
return static_cast<int16_t *>(TypedArray::getDataOffset(obj));
@ -3305,7 +3414,8 @@ JS_GetInt16ArrayData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(uint16_t *)
JS_GetUint16ArrayData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isTypedArray());
JS_ASSERT(obj->getSlot(TypedArray::FIELD_TYPE).toInt32() == ArrayBufferView::TYPE_UINT16);
return static_cast<uint16_t *>(TypedArray::getDataOffset(obj));
@ -3314,7 +3424,8 @@ JS_GetUint16ArrayData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(int32_t *)
JS_GetInt32ArrayData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isTypedArray());
JS_ASSERT(obj->getSlot(TypedArray::FIELD_TYPE).toInt32() == ArrayBufferView::TYPE_INT32);
return static_cast<int32_t *>(TypedArray::getDataOffset(obj));
@ -3323,7 +3434,8 @@ JS_GetInt32ArrayData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(uint32_t *)
JS_GetUint32ArrayData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isTypedArray());
JS_ASSERT(obj->getSlot(TypedArray::FIELD_TYPE).toInt32() == ArrayBufferView::TYPE_UINT32);
return static_cast<uint32_t *>(TypedArray::getDataOffset(obj));
@ -3332,7 +3444,8 @@ JS_GetUint32ArrayData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(float *)
JS_GetFloat32ArrayData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isTypedArray());
JS_ASSERT(obj->getSlot(TypedArray::FIELD_TYPE).toInt32() == ArrayBufferView::TYPE_FLOAT32);
return static_cast<float *>(TypedArray::getDataOffset(obj));
@ -3341,7 +3454,8 @@ JS_GetFloat32ArrayData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(double *)
JS_GetFloat64ArrayData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isTypedArray());
JS_ASSERT(obj->getSlot(TypedArray::FIELD_TYPE).toInt32() == ArrayBufferView::TYPE_FLOAT64);
return static_cast<double *>(TypedArray::getDataOffset(obj));
@ -3350,7 +3464,8 @@ JS_GetFloat64ArrayData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(JSBool)
JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return false;
*isDataView = obj->isDataView();
return true;
}
@ -3358,14 +3473,16 @@ JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView)
JS_FRIEND_API(uint32_t)
JS_GetDataViewByteOffset(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return 0;
return obj->asDataView().byteOffset();
}
JS_FRIEND_API(void *)
JS_GetDataViewData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isDataView());
return obj->asDataView().dataPointer();
}
@ -3373,7 +3490,8 @@ JS_GetDataViewData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(uint32_t)
JS_GetDataViewByteLength(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return 0;
JS_ASSERT(obj->isDataView());
return obj->asDataView().byteLength();
}
@ -3381,7 +3499,8 @@ JS_GetDataViewByteLength(JSObject *obj, JSContext *cx)
JS_FRIEND_API(void *)
JS_GetArrayBufferViewData(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return NULL;
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
return obj->isDataView() ? obj->asDataView().dataPointer() : TypedArray::getDataOffset(obj);
}
@ -3389,7 +3508,8 @@ JS_GetArrayBufferViewData(JSObject *obj, JSContext *cx)
JS_FRIEND_API(uint32_t)
JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx)
{
obj = UnwrapObject(obj);
if (!(obj = CheckedUnwrap(cx, obj)))
return 0;
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
return obj->isDataView() ? obj->asDataView().byteLength() : TypedArray::getByteLength(obj);
}

View File

@ -330,9 +330,12 @@ class DataViewObject : public JSObject
static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp);
static JSBool class_constructor(JSContext *cx, unsigned argc, Value *vp);
static JSBool constructWithProto(JSContext *cx, unsigned argc, Value *vp);
static JSBool construct(JSContext *cx, JSObject *bufobj, const CallArgs &args, JSObject *proto);
static inline DataViewObject *
create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength, Handle<ArrayBufferObject*> arrayBuffer);
create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
Handle<ArrayBufferObject*> arrayBuffer, JSObject *proto);
static JSBool fun_getInt8(JSContext *cx, unsigned argc, Value *vp);
static JSBool fun_getUint8(JSContext *cx, unsigned argc, Value *vp);

View File

@ -129,7 +129,7 @@ TypedArray::getDataOffset(JSObject *obj) {
inline DataViewObject *
DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
Handle<ArrayBufferObject*> arrayBuffer)
Handle<ArrayBufferObject*> arrayBuffer, JSObject *proto)
{
JS_ASSERT(byteOffset <= INT32_MAX);
JS_ASSERT(byteLength <= INT32_MAX);
@ -138,6 +138,21 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
if (!obj)
return NULL;
types::TypeObject *type;
if (proto) {
type = proto->getNewType(cx);
} else {
/*
* Specialize the type of the object on the current scripted location,
* and mark the type as definitely a data view
*/
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(&DataViewClass);
type = types::GetTypeCallerInitObject(cx, key);
if (!type)
return NULL;
}
obj->setType(type);
JS_ASSERT(arrayBuffer->isArrayBuffer());
DataViewObject &dvobj = obj->asDataView();

View File

@ -793,7 +793,7 @@ CrossCompartmentWrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *cla
JS_ASSERT_IF(!srcArgs.calleev().isUndefined(),
srcArgs.callee().toFunction()->native() == native ||
srcArgs.callee().toFunction()->native() == js_generic_native_method_dispatcher);
JS_ASSERT(&srcArgs.thisv().toObject() == wrapper);
JS_ASSERT(srcArgs.thisv().isMagic(JS_IS_CONSTRUCTING) || &srcArgs.thisv().toObject() == wrapper);
JS_ASSERT(!UnwrapObject(wrapper)->isCrossCompartmentWrapper());
JSObject *wrapped = wrappedObject(wrapper);

View File

@ -1302,6 +1302,13 @@ JITScript::destroyChunk(FreeOp *fop, unsigned chunkIndex, bool resetUses)
ChunkDescriptor &desc = chunkDescriptor(chunkIndex);
if (desc.chunk) {
/*
* Write barrier: Before we destroy the chunk, trace through the objects
* it holds.
*/
if (script->compartment()->needsBarrier())
desc.chunk->trace(script->compartment()->barrierTracer());
Probes::discardMJITCode(fop, this, desc.chunk, desc.chunk->code.m_code.executableAddress());
fop->delete_(desc.chunk);
desc.chunk = NULL;
@ -1532,8 +1539,10 @@ void
JITChunk::trace(JSTracer *trc)
{
JSObject **rootedTemplates_ = rootedTemplates();
for (size_t i = 0; i < nRootedTemplates; i++)
for (size_t i = 0; i < nRootedTemplates; i++) {
/* We use a manual write barrier in destroyChunk. */
MarkObjectUnbarriered(trc, &rootedTemplates_[i], "jitchunk_template");
}
}
void

View File

@ -1626,6 +1626,11 @@ function test() {
buffer = Object.create(buffer1);
checkThrow(function () new DataView(buffer), TypeError);
// view of proxy for buffer
av = new DataView(alien_buffer);
assertEq(av.getUint8(4), 100);
assertEq(Object.getPrototypeOf(av), DataView.prototype);
reportCompare(0, 0, 'done.');
exitFunc ('test');
}

View File

@ -1,3 +1,4 @@
// |reftest| skip-if(!xulRuntime.shell)
/* -*- Mode: js2; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* Any copyright is dedicated to the Public Domain.
@ -424,6 +425,33 @@ function test()
// use a loop to invoke the TM
for (var i = 0; i < b.length; i++)
check(function() b[90] == 5)
// Protos and proxies, oh my!
var alien = newGlobal('new-compartment');
var alien_view = alien.eval('view = new Uint8Array(7)');
var alien_buffer = alien.eval('buffer = view.buffer');
// when creating a view of a buffer in a different compartment, the view
// itself should be created in the other compartment and wrapped for use in
// this compartment. (There should never be a compartment boundary between
// an ArrayBufferView and its ArrayBuffer.)
var view = new Int8Array(alien_buffer);
// First make sure they're looking at the same data
alien_view[3] = 77;
check(function () view[3] == 77);
// Now check that the proxy setup is as expected
check(function () isProxy(alien_view));
check(function () isProxy(alien_buffer));
check(function () isProxy(view)); // the real test
// typed array protos should be equal
simple = new Int8Array(12);
check(function () Object.getPrototypeOf(view) == Object.getPrototypeOf(simple));
check(function () Object.getPrototypeOf(view) == Int8Array.prototype);
print ("done");
reportCompare(0, TestFailCount, "typed array tests");

View File

@ -1481,12 +1481,17 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
"Memory allocated for JSScript bytecode and various "
"variable-length tables.");
REPORT_BYTES0(MakePath(pathPrefix, cStats, "mjit/data"),
REPORT_BYTES0(MakePath(pathPrefix, cStats, "mjit-data"),
nsIMemoryReporter::KIND_HEAP, cStats.mjitData,
"Memory used by the method JIT for the compartment's "
"compilation data: JITScripts, native maps, and inline "
"cache structs.");
REPORT_BYTES0(MakePath(pathPrefix, cStats, "cross-compartment-wrappers"),
nsIMemoryReporter::KIND_HEAP, cStats.crossCompartmentWrappers,
"Memory used by the compartment's cross-compartment "
"wrappers.");
REPORT_BYTES0(MakePath(pathPrefix, cStats, "type-inference/script-main"),
nsIMemoryReporter::KIND_HEAP,
cStats.typeInferenceSizes.scripts,
@ -1533,52 +1538,66 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
}
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeObject,
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.object,
"Memory used by the JSRuntime object.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/atoms-table"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeAtomsTable,
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.atomsTable,
"Memory used by the atoms table.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/contexts"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeContexts,
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.contexts,
"Memory used by JSContext objects and certain structures "
"hanging off them.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/normal"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeNormal,
"Memory used by a JSRuntime, excluding memory that is "
"reported by other reporters under 'explicit/js/runtime/'.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/dtoa"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.dtoa,
"Memory used by DtoaState, which is used for converting "
"strings to numbers and vice versa.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/temporary"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeTemporary,
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.temporary,
"Memory held transiently in JSRuntime and used during "
"compilation. It mostly holds parse nodes.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/mjit-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeMjitCode,
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.mjitCode,
"Memory used by the method JIT to hold the runtime's "
"generated code.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/regexp-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeRegexpCode,
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.regexpCode,
"Memory used by the regexp JIT to hold generated code.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/unused-code-memory"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeUnusedCodeMemory,
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.unusedCodeMemory,
"Memory allocated by the method and/or regexp JIT to hold the "
"runtime's code, but which is currently unused.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/stack-committed"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeStackCommitted,
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.stackCommitted,
"Memory used for the JS call stack. This is the committed "
"portion of the stack; the uncommitted portion is not "
"measured because it hardly costs anything.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/gc-marker"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeGCMarker,
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.gcMarker,
"Memory used for the GC mark stack and gray roots.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/math-cache"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.mathCache,
"Memory used for the math cache.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/script-filenames"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.scriptFilenames,
"Memory used for the table holding script filenames.");
REPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("runtime/compartment-objects"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.compartmentObjects,
"Memory used for JSCompartment objects. These are fairly "
"small and all the same size, so they're not worth reporting "
"on a per-compartment basis.");
REPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
rtStats.gcHeapChunkDirtyUnused,
"Memory on the garbage-collected JavaScript heap, within "

View File

@ -16,6 +16,7 @@ dictionaries = [
[ 'SettingsEventInit', 'nsIDOMSettingsManager.idl' ],
[ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ],
[ 'DeviceProximityEventInit', 'nsIDOMDeviceProximityEvent.idl' ],
[ 'UserProximityEventInit', 'nsIDOMUserProximityEvent.idl' ],
[ 'DeviceLightEventInit', 'nsIDOMDeviceLightEvent.idl' ]
]

View File

@ -146,6 +146,10 @@ def print_header_file(fd, conf):
"#include \"nsString.h\"\n"
"#include \"nsCOMPtr.h\"\n\n")
# win32 namespace issues
fd.write("#undef near\n"
"\n\n")
forwards = []
attrnames = []
for d in conf.dictionaries:

View File

@ -1162,7 +1162,11 @@ ContainerState::ThebesLayerData::UpdateCommonClipCount(
already_AddRefed<ImageContainer>
ContainerState::ThebesLayerData::CanOptimizeImageLayer()
{
#ifdef MOZ_ENABLE_MASK_LAYERS
if (!mImage) {
#else
if (!mImage || !mItemClip.mRoundedClipRects.IsEmpty()) {
#endif
return nsnull;
}
@ -1192,6 +1196,10 @@ ContainerState::PopThebesLayerData()
gfx3DMatrix transform = imageLayer->GetTransform()*
gfx3DMatrix::ScalingMatrix(mParameters.mXScale, mParameters.mYScale, 1.0f);
imageLayer->SetTransform(transform);
#ifndef MOZ_ENABLE_MASK_LAYERS
NS_ASSERTION(data->mItemClip.mRoundedClipRects.IsEmpty(),
"How did we get rounded clip rects here?");
#endif
if (data->mItemClip.mHaveClipRect) {
nsIntRect clip = ScaleToNearestPixels(data->mItemClip.mClipRect);
imageLayer->IntersectClipRect(clip);
@ -1273,6 +1281,7 @@ ContainerState::PopThebesLayerData()
}
userData->mForcedBackgroundColor = backgroundColor;
#ifdef MOZ_ENABLE_MASK_LAYERS
// use a mask layer for rounded rect clipping
PRInt32 commonClipCount = data->mCommonClipCount;
NS_ASSERTION(commonClipCount >= 0, "Inconsistent clip count.");
@ -1284,6 +1293,7 @@ ContainerState::PopThebesLayerData()
} else {
// mask layer for image and color layers
SetupMaskLayer(layer, data->mItemClip);
#endif
}
PRUint32 flags;
if (isOpaque && !data->mForceTransparentSurface) {
@ -1646,7 +1656,13 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
// Assign the item to a layer
if (layerState == LAYER_ACTIVE_FORCE ||
layerState == LAYER_ACTIVE_EMPTY ||
#ifdef MOZ_ENABLE_MASK_LAYERS
layerState == LAYER_ACTIVE) {
#else
(layerState == LAYER_ACTIVE &&
(aClip.mRoundedClipRects.IsEmpty() ||
!aClip.IsRectClippedByRoundedCorner(item->GetVisibleRect())))) {
#endif
// LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
// We should never see an empty layer with any visible content!
@ -1707,11 +1723,13 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
}
RestrictVisibleRegionForLayer(ownLayer, itemVisibleRect);
#ifdef MOZ_ENABLE_MASK_LAYERS
// rounded rectangle clipping using mask layers
// (must be done after visible rect is set on layer)
if (aClip.IsRectClippedByRoundedCorner(itemContent)) {
SetupMaskLayer(ownLayer, aClip);
}
#endif
ContainerLayer* oldContainer = ownLayer->GetParent();
if (oldContainer && oldContainer != mContainerLayer) {
@ -2802,6 +2820,7 @@ void
ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aClip,
PRUint32 aRoundedRectClipCount)
{
#ifdef MOZ_ENABLE_MASK_LAYERS
// don't build an unnecessary mask
if (aClip.mRoundedClipRects.IsEmpty() ||
aRoundedRectClipCount <= 0) {
@ -2890,6 +2909,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
userData->mBounds = aLayer->GetEffectiveVisibleRegion().GetBounds();
aLayer->SetMaskLayer(maskLayer);
#endif
return;
}

View File

@ -6771,26 +6771,6 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
nsRect& o = aOverflowAreas.Overflow(otype);
o.UnionRectEdges(o, bounds);
}
if (!nsLayoutUtils::IsPopup(this)) {
// Include margin in scrollable overflow.
// XXX In theory this should consider margin collapsing
nsRect marginBounds(bounds);
nsMargin margin = GetUsedMargin();
// Bug 724352 - vertical scrollable overflow only matters for
// scroll frames which are block margin roots and has already
// accumulated child vertical margins during reflow. We need
// to revisit this when using UpdateOverflow for non-transform
// style changes (bug 719177).
margin.top = 0;
margin.bottom = 0;
ApplySkipSides(margin);
marginBounds.SaturatingInflate(margin);
nsRect& so = aOverflowAreas.ScrollableOverflow();
so.SaturatingUnionRectEdges(so, marginBounds);
}
}
// Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background,

View File

@ -1847,6 +1847,12 @@ CanScrollWithBlitting(nsIFrame* aFrame)
f->IsFrameOfType(nsIFrame::eSVG)) {
return false;
}
#ifndef MOZ_ENABLE_MASK_LAYERS
nsIScrollableFrame* sf = do_QueryFrame(f);
if ((sf || f->IsFrameOfType(nsIFrame::eReplaced)) &&
nsLayoutUtils::HasNonZeroCorner(f->GetStyleBorder()->mBorderRadius))
return false;
#endif
if (nsLayoutUtils::IsPopup(f))
break;
}

View File

@ -1,8 +1,9 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
<hbox style="-moz-appearance: textfield-multiline; width: 200px; height: 200px;"/>
<html:div style="position:fixed;top:0;left:0;width:100%;height:100%;"></html:div>
</window>

View File

@ -1,8 +1,8 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<html:textarea xmlns:html="http://www.w3.org/1999/xhtml" style="width: 200px; height: 200px; margin: 0; resize: none;"/>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
<html:textarea style="width: 200px; height: 200px; margin: 0; resize: none;"/>
<html:div style="position:fixed;top:0;left:0;width:100%;height:100%;"></html:div>
</window>

View File

@ -11,14 +11,14 @@
x1,x2,x3,x4,x5,x6 { display:block; }
x2 { overflow:auto; width:100px; background:grey; }
x4 { width: 70px; }
x3 { width: 70px; padding: 0 20px; }
x3 { width: 70px; padding-left: 20px; padding-right: 10px; }
</style>
</head>
<body>
<x1><x2 style="height:50px;">
<x3><x4 style="height:20px; background:lime; "></x4></x3>
</x2>
</x2></x1>
</body>

View File

@ -17,7 +17,7 @@ x4 { width: 70px; margin: 0 20px; }
<x1><x2 style="height:50px;">
<x4 style="height:20px; background:lime; "></x4>
</x2>
</x2></x1>
</body>

View File

@ -48,6 +48,11 @@ html,body {
}
span { background-color:white; position: relative; }
ml3 {position: absolute; left:29ch; }
#block-hover {
position:fixed;
top:0;left:0;width:100%;height:100%;
}
</style>
</head>
<body>
@ -70,5 +75,6 @@ ml3 {position: absolute; left:29ch; }
<div class="bacon scroll4"><span>6Beef hamburger bacon tri-ti JOWLBILTONG tail ribeye ham</span></div><br>
</div>
<div id="block-hover"></div>
</body>
</html>

View File

@ -53,6 +53,10 @@ html,body {
}
span { background-color:white; }
#block-hover {
position:fixed;
top:0;left:0;width:100%;height:100%;
}
</style>
</head>
<body onload="document.getElementById('rtl_auto').scrollLeft=999999; document.documentElement.removeAttribute('class')">
@ -75,5 +79,6 @@ span { background-color:white; }
<div class="bacon scroll4"><span>6Beef hamburger bacon tri-tipJOWLBILTONG tail ribeye ham</span></div><br>
</div>
<div id="block-hover"></div>
</body>
</html>

View File

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="data:text/css,u { display: inline; text-decoration: underline; }" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<hbox align="start">
<label control="b1"><u>L</u>abel1</label><textbox id="b1" size="2"/>
<label control="b2">Labe<u>l</u>2</label><textbox id="b2" size="2"/>
<label control="b3">La<u>b</u>el3</label><textbox id="b3" size="2"/>
<label control="b4">Label4 (<u>X</u>)</label><textbox id="b4" size="2"/>
<label control="b5" maxwidth="50">Quite a <u>l</u>ong label. Hopefully it will wrap</label><textbox id="b5" label="Button5" size="2"/>
</hbox>
<hbox id="d" align="start">
<label control="d1"><u>L</u>abel1</label><textbox id="d1" size="2"/>
<label control="d2">Labe<u>l</u>2</label><textbox id="d2" size="2"/>
<label control="d3">La<u>b</u>el3</label><textbox id="d3" size="2"/>
<label control="d4">Label4 (<u>X</u>)</label><textbox id="d4" size="2"/>
<label control="d5" maxwidth="50">Quite a <u>l</u>ong label. Hopefully it will wrap</label><textbox id="d5" size="2"/>
</hbox>
</window>

View File

@ -0,0 +1,43 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<!-- This test checks that access keys are rendered properly, both when set with the
accesskey attribute in the markup and updated via script later.
-->
<window class="reftest-wait" onload="changeKeys()"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script>
<![CDATA[
var keys = ['L', 'l', 'b', 'x', 'l'];
function changeKeys()
{
var box = document.getElementById('d');
for (var b = 0; b < 5; b++)
box.childNodes[b * 2].accessKey = keys[b];
document.documentElement.className='';
}
]]>
</script>
<hbox align="start">
<label control="b1">Label1</label><textbox id="b1" accesskey="L" size="2"/>
<label control="b2">Label2</label><textbox id="b2" accesskey="l" size="2"/>
<label control="b3">Label3</label><textbox id="b3" accesskey="b" size="2"/>
<label control="b4">Label4</label><textbox id="b4" accesskey="x" size="2"/>
<label control="b5" maxwidth="50">Quite a long label. Hopefully it will wrap</label><textbox id="b5" accesskey="l" size="2"/>
</hbox>
<hbox id="d" align="start">
<label control="d1">Label1</label><textbox id="d1" accesskey="z" size="2"/>
<label control="d2">Label2</label><textbox id="d2" size="2"/>
<label control="d3">Label3</label><textbox id="d3" accesskey="t" size="2"/>
<label control="d4">Label4</label><textbox id="d4" accesskey="b" size="2"/>
<label control="d5" maxwidth="50">Quite a long label. Hopefully it will wrap</label><textbox id="d5" accesskey="l" size="2"/>
</hbox>
</window>

View File

@ -3,3 +3,5 @@
random-if(Android) == menulist-shrinkwrap-1.xul menulist-shrinkwrap-1-ref.xul
random-if(Android) fails-if(winWidget) == menulist-shrinkwrap-2.xul menulist-shrinkwrap-2-ref.xul
== textbox-overflow-1.xul textbox-overflow-1-ref.xul # for bug 749658
# accesskeys are not normally displayed on Mac, so skip this test
skip-if(cocoaWidget) == accesskey.xul accesskey-ref.xul

View File

@ -126,8 +126,7 @@
<activity android:name="Restarter"
android:process="@ANDROID_PACKAGE_NAME@Restarter"
android:theme="@style/Gecko"
android:excludeFromRecents="true">
android:theme="@style/Gecko">
<intent-filter>
<action android:name="org.mozilla.gecko.restart"/>
<action android:name="org.mozilla.gecko.restart_update"/>

View File

@ -1525,6 +1525,14 @@ abstract public class GeckoApp
mAppContext = this;
// Check to see if the activity is restarted after configuration change.
if (getLastNonConfigurationInstance() != null) {
// Restart the application as a safe way to handle the configuration change.
doRestart();
System.exit(0);
return;
}
// StrictMode is set by defaults resource flag |enableStrictMode|.
if (getResources().getBoolean(R.bool.enableStrictMode)) {
enableStrictMode();
@ -2137,6 +2145,13 @@ abstract public class GeckoApp
GeckoScreenOrientationListener.getInstance().start();
}
@Override
public Object onRetainNonConfigurationInstance() {
// Send a non-null value so that we can restart the application,
// when activity restarts due to configuration change.
return new Boolean(true);
}
abstract public String getPackageName();
abstract public String getContentProcessName();

View File

@ -85,6 +85,7 @@ public class Restarter extends Activity {
if (b != null)
intent.putExtras(b);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Log.i(LOGTAG, intent.toString());
startActivity(intent);
} catch (Exception e) {

View File

@ -46,7 +46,7 @@ extern "C" {
typedef enum {
SNAPPY_OK = 0,
SNAPPY_INVALID_INPUT = 1,
SNAPPY_BUFFER_TOO_SMALL = 2,
SNAPPY_BUFFER_TOO_SMALL = 2
} snappy_status;
/*

View File

@ -4,7 +4,7 @@ This pywebsocket code is mostly unchanged from the source at
The current Mozilla code is based on
svnversion: 606 (supports RFC 6455, aka Sec-WebSocket-Version: 13)
svnversion: 631 (supports RFC 6455)
--------------------------------------------------------------------------------
STEPS TO UPDATE MOZILLA TO NEWER PYWEBSOCKET VERSION
@ -20,7 +20,7 @@ STEPS TO UPDATE MOZILLA TO NEWER PYWEBSOCKET VERSION
- rsync new version into our tree, deleting files that aren't needed any more
(NOTE: this will blow away this file! hg revert it or keep a copy.)
rsync -r --delete dist/ $MOZ_SRC/testing/mochitest/pywebsocket
rsync -rv --delete dist/ $MOZ_SRC/testing/mochitest/pywebsocket
- Get rid of examples/test directory and some cruft:

View File

@ -28,8 +28,11 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Stream of WebSocket protocol with the framing used by IETF HyBi 00 and
Hixie 75. For Hixie 75 this stream doesn't perform closing handshake.
"""This file provides a class for parsing/building frames of the WebSocket
protocol version HyBi 00 and Hixie 75.
Specification:
http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
"""
@ -43,7 +46,9 @@ from mod_pywebsocket import util
class StreamHixie75(StreamBase):
"""Stream of WebSocket messages."""
"""A class for parsing/building frames of the WebSocket protocol version
HyBi 00 and Hixie 75.
"""
def __init__(self, request, enable_closing_handshake=False):
"""Construct an instance.

View File

@ -1,4 +1,4 @@
# Copyright 2011, Google Inc.
# Copyright 2012, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -28,7 +28,11 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Stream class for IETF HyBi latest WebSocket protocol.
"""This file provides classes and helper functions for parsing/building frames
of the WebSocket protocol (RFC 6455).
Specification:
http://tools.ietf.org/html/rfc6455
"""
@ -238,7 +242,9 @@ class StreamOptions(object):
class Stream(StreamBase):
"""Stream of WebSocket messages."""
"""A class for parsing/building frames of the WebSocket protocol
(RFC 6455).
"""
def __init__(self, request, options):
"""Constructs an instance.
@ -353,8 +359,8 @@ class Stream(StreamBase):
Raises:
BadOperationException: when called on a server-terminated
connection or called with inconsistent message type or binary
parameter.
connection or called with inconsistent message type or
binary parameter.
"""
if self._request.server_terminated:
@ -482,7 +488,11 @@ class Stream(StreamBase):
# - no application data: no code no reason
# - 2 octet of application data: has code but no reason
# - 3 or more octet of application data: both code and reason
if len(message) == 1:
if len(message) == 0:
self._logger.debug('Received close frame (empty body)')
self._request.ws_close_code = (
common.STATUS_NO_STATUS_RECEIVED)
elif len(message) == 1:
raise InvalidFrameException(
'If a close frame has status code, the length of '
'status code must be 2 octet')
@ -501,22 +511,28 @@ class Stream(StreamBase):
if self._request.server_terminated:
self._logger.debug(
'Received ack for server-initiated closing '
'handshake')
'Received ack for server-initiated closing handshake')
return None
self._logger.debug(
'Received client-initiated closing handshake')
code = common.STATUS_NORMAL
code = common.STATUS_NORMAL_CLOSURE
reason = ''
if hasattr(self._request, '_dispatcher'):
dispatcher = self._request._dispatcher
code, reason = dispatcher.passive_closing_handshake(
self._request)
if code is None and reason is not None and len(reason) > 0:
self._logger.warning(
'Handler specified reason despite code being None')
reason = ''
if reason is None:
reason = ''
self._send_closing_handshake(code, reason)
self._logger.debug(
'Sent ack for client-initiated closing handshake')
'Sent ack for client-initiated closing handshake '
'(code=%r, reason=%r)', code, reason)
return None
elif self._original_opcode == common.OPCODE_PING:
try:
@ -565,17 +581,19 @@ class Stream(StreamBase):
'Opcode %d is not supported' % self._original_opcode)
def _send_closing_handshake(self, code, reason):
if code >= (1 << 16) or code < 0:
raise BadOperationException('Status code is out of range')
encoded_reason = reason.encode('utf-8')
if len(encoded_reason) + 2 > 125:
raise BadOperationException(
'Application data size of close frames must be 125 bytes or '
'less')
body = ''
if code is not None:
if code >= (1 << 16) or code < 0:
raise BadOperationException('Status code is out of range')
encoded_reason = reason.encode('utf-8')
if len(encoded_reason) + 2 > 125:
raise BadOperationException(
'Application data size of close frames must be 125 bytes '
'or less')
body = struct.pack('!H', code) + encoded_reason
frame = create_close_frame(
struct.pack('!H', code) + encoded_reason,
body,
self._options.mask_send,
self._options.outgoing_frame_filters)
@ -583,16 +601,37 @@ class Stream(StreamBase):
self._write(frame)
def close_connection(self, code=common.STATUS_NORMAL, reason=''):
"""Closes a WebSocket connection."""
def close_connection(self, code=common.STATUS_NORMAL_CLOSURE, reason=''):
"""Closes a WebSocket connection.
Args:
code: Status code for close frame. If code is None, a close
frame with empty body will be sent.
reason: string representing close reason.
Raises:
BadOperationException: when reason is specified with code None
or reason is not an instance of both str and unicode.
"""
if self._request.server_terminated:
self._logger.debug(
'Requested close_connection but server is already terminated')
return
if code is None:
if reason is not None and len(reason) > 0:
raise BadOperationException(
'close reason must not be specified if code is None')
reason = ''
else:
if not isinstance(reason, str) and not isinstance(reason, unicode):
raise BadOperationException(
'close reason must be an instance of str or unicode')
self._send_closing_handshake(code, reason)
self._logger.debug('Sent server-initiated closing handshake')
self._logger.debug(
'Sent server-initiated closing handshake (code=%r, reason=%r)',
code, reason)
if (code == common.STATUS_GOING_AWAY or
code == common.STATUS_PROTOCOL_ERROR):

View File

@ -1,4 +1,4 @@
# Copyright 2011, Google Inc.
# Copyright 2012, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -93,21 +93,41 @@ SEC_WEBSOCKET_LOCATION_HEADER = 'Sec-WebSocket-Location'
# Extensions
DEFLATE_STREAM_EXTENSION = 'deflate-stream'
DEFLATE_FRAME_EXTENSION = 'deflate-frame'
X_WEBKIT_DEFLATE_FRAME_EXTENSION = 'x-webkit-deflate-frame'
# Status codes
# Code STATUS_CODE_NOT_AVAILABLE should not be used in actual frames. This code
# is exposed to JavaScript API as pseudo status code which represent actual
# frame does not have status code.
STATUS_NORMAL = 1000
# Code STATUS_NO_STATUS_RECEIVED, STATUS_ABNORMAL_CLOSURE, and
# STATUS_TLS_HANDSHAKE are pseudo codes to indicate specific error cases.
# Could not be used for codes in actual closing frames.
# Application level errors must use codes in the range
# STATUS_USER_REGISTERED_BASE to STATUS_USER_PRIVATE_MAX. The codes in the
# range STATUS_USER_REGISTERED_BASE to STATUS_USER_REGISTERED_MAX are managed
# by IANA. Usually application must define user protocol level errors in the
# range STATUS_USER_PRIVATE_BASE to STATUS_USER_PRIVATE_MAX.
STATUS_NORMAL_CLOSURE = 1000
STATUS_GOING_AWAY = 1001
STATUS_PROTOCOL_ERROR = 1002
STATUS_UNSUPPORTED = 1003
STATUS_CODE_NOT_AVAILABLE = 1005
STATUS_ABNORMAL_CLOSE = 1006
STATUS_INVALID_FRAME_PAYLOAD = 1007
STATUS_UNSUPPORTED_DATA = 1003
STATUS_NO_STATUS_RECEIVED = 1005
STATUS_ABNORMAL_CLOSURE = 1006
STATUS_INVALID_FRAME_PAYLOAD_DATA = 1007
STATUS_POLICY_VIOLATION = 1008
STATUS_MESSAGE_TOO_BIG = 1009
STATUS_MANDATORY_EXT = 1010
STATUS_MANDATORY_EXTENSION = 1010
STATUS_INTERNAL_SERVER_ERROR = 1011
STATUS_TLS_HANDSHAKE = 1015
STATUS_USER_REGISTERED_BASE = 3000
STATUS_USER_REGISTERED_MAX = 3999
STATUS_USER_PRIVATE_BASE = 4000
STATUS_USER_PRIVATE_MAX = 4999
# Following definitions are aliases to keep compatibility. Applications must
# not use these obsoleted definitions anymore.
STATUS_NORMAL = STATUS_NORMAL_CLOSURE
STATUS_UNSUPPORTED = STATUS_UNSUPPORTED_DATA
STATUS_CODE_NOT_AVAILABLE = STATUS_NO_STATUS_RECEIVED
STATUS_ABNORMAL_CLOSE = STATUS_ABNORMAL_CLOSURE
STATUS_INVALID_FRAME_PAYLOAD = STATUS_INVALID_FRAME_PAYLOAD_DATA
STATUS_MANDATORY_EXT = STATUS_MANDATORY_EXTENSION
# HTTP status codes
HTTP_STATUS_BAD_REQUEST = 400

View File

@ -1,4 +1,4 @@
# Copyright 2011, Google Inc.
# Copyright 2012, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -62,7 +62,7 @@ class DispatchException(Exception):
def _default_passive_closing_handshake_handler(request):
"""Default web_socket_passive_closing_handshake handler."""
return common.STATUS_NORMAL, ''
return common.STATUS_NORMAL_CLOSURE, ''
def _normalize_path(path):
@ -292,7 +292,7 @@ class Dispatcher(object):
raise
except msgutil.BadOperationException, e:
self._logger.debug('%s', e)
request.ws_stream.close_connection(common.STATUS_ABNORMAL_CLOSE)
request.ws_stream.close_connection(common.STATUS_ABNORMAL_CLOSURE)
except msgutil.InvalidFrameException, e:
# InvalidFrameException must be caught before
# ConnectionTerminatedException that catches InvalidFrameException.
@ -300,11 +300,11 @@ class Dispatcher(object):
request.ws_stream.close_connection(common.STATUS_PROTOCOL_ERROR)
except msgutil.UnsupportedFrameException, e:
self._logger.debug('%s', e)
request.ws_stream.close_connection(common.STATUS_UNSUPPORTED)
request.ws_stream.close_connection(common.STATUS_UNSUPPORTED_DATA)
except stream.InvalidUTF8Exception, e:
self._logger.debug('%s', e)
request.ws_stream.close_connection(
common.STATUS_INVALID_FRAME_PAYLOAD)
common.STATUS_INVALID_FRAME_PAYLOAD_DATA)
except msgutil.ConnectionTerminatedException, e:
self._logger.debug('%s', e)
except Exception, e:

View File

@ -72,7 +72,7 @@ _available_processors[common.DEFLATE_STREAM_EXTENSION] = (
class DeflateFrameExtensionProcessor(ExtensionProcessorInterface):
"""WebSocket Per-frame DEFLATE extension processor."""
_WINDOW_BITS_PARAM = 'window_bits'
_WINDOW_BITS_PARAM = 'max_window_bits'
_NO_CONTEXT_TAKEOVER_PARAM = 'no_context_takeover'
def __init__(self, request):
@ -83,6 +83,18 @@ class DeflateFrameExtensionProcessor(ExtensionProcessorInterface):
self._response_window_bits = None
self._response_no_context_takeover = False
# Counters for statistics.
# Total number of outgoing bytes supplied to this filter.
self._total_outgoing_payload_bytes = 0
# Total number of bytes sent to the network after applying this filter.
self._total_filtered_outgoing_payload_bytes = 0
# Total number of bytes received from the network.
self._total_incoming_payload_bytes = 0
# Total number of incoming bytes obtained after applying this filter.
self._total_filtered_incoming_payload_bytes = 0
def get_extension_response(self):
# Any unknown parameter will be just ignored.
@ -110,7 +122,7 @@ class DeflateFrameExtensionProcessor(ExtensionProcessorInterface):
self._compress_outgoing = True
response = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
response = common.ExtensionParameter(self._request.name())
if self._response_window_bits is not None:
response.add_parameter(
@ -123,7 +135,7 @@ class DeflateFrameExtensionProcessor(ExtensionProcessorInterface):
'Enable %s extension ('
'request: window_bits=%s; no_context_takeover=%r, '
'response: window_wbits=%s; no_context_takeover=%r)' %
(common.DEFLATE_STREAM_EXTENSION,
(self._request.name(),
window_bits,
no_context_takeover,
self._response_window_bits,
@ -171,29 +183,77 @@ class DeflateFrameExtensionProcessor(ExtensionProcessorInterface):
an _OutgoingFilter instance.
"""
original_payload_size = len(frame.payload)
self._total_outgoing_payload_bytes += original_payload_size
if (not self._compress_outgoing or
common.is_control_opcode(frame.opcode)):
self._total_filtered_outgoing_payload_bytes += (
original_payload_size)
return
frame.payload = self._deflater.filter(frame.payload)
frame.rsv1 = 1
filtered_payload_size = len(frame.payload)
self._total_filtered_outgoing_payload_bytes += filtered_payload_size
# Print inf when ratio is not available.
ratio = float('inf')
average_ratio = float('inf')
if original_payload_size != 0:
ratio = float(filtered_payload_size) / original_payload_size
if self._total_outgoing_payload_bytes != 0:
average_ratio = (
float(self._total_filtered_outgoing_payload_bytes) /
self._total_outgoing_payload_bytes)
self._logger.debug(
'Outgoing compress ratio: %f (average: %f)' %
(ratio, average_ratio))
def _incoming_filter(self, frame):
"""Transform incoming frames. This method is called only by
an _IncomingFilter instance.
"""
received_payload_size = len(frame.payload)
self._total_incoming_payload_bytes += received_payload_size
if frame.rsv1 != 1 or common.is_control_opcode(frame.opcode):
self._total_filtered_incoming_payload_bytes += (
received_payload_size)
return
frame.payload = self._inflater.filter(frame.payload)
frame.rsv1 = 0
filtered_payload_size = len(frame.payload)
self._total_filtered_incoming_payload_bytes += filtered_payload_size
# Print inf when ratio is not available.
ratio = float('inf')
average_ratio = float('inf')
if received_payload_size != 0:
ratio = float(received_payload_size) / filtered_payload_size
if self._total_filtered_incoming_payload_bytes != 0:
average_ratio = (
float(self._total_incoming_payload_bytes) /
self._total_filtered_incoming_payload_bytes)
self._logger.debug(
'Incoming compress ratio: %f (average: %f)' %
(ratio, average_ratio))
_available_processors[common.DEFLATE_FRAME_EXTENSION] = (
DeflateFrameExtensionProcessor)
# Adding vendor-prefixed deflate-frame extension.
# TODO(bashi): Remove this after WebKit stops using vender prefix.
_available_processors[common.X_WEBKIT_DEFLATE_FRAME_EXTENSION] = (
DeflateFrameExtensionProcessor)
def get_extension_processor(extension_request):
global _available_processors
processor_class = _available_processors.get(extension_request.name())

View File

@ -83,15 +83,15 @@ def do_handshake(request, dispatcher, allowDraft75=False, strict=False):
handshakers = []
handshakers.append(
('IETF HyBi latest', hybi.Handshaker(request, dispatcher)))
('RFC 6455', hybi.Handshaker(request, dispatcher)))
handshakers.append(
('IETF HyBi 00', hybi00.Handshaker(request, dispatcher)))
('HyBi 00', hybi00.Handshaker(request, dispatcher)))
if allowDraft75:
handshakers.append(
('IETF Hixie 75', draft75.Handshaker(request, dispatcher, strict)))
('Hixie 75', draft75.Handshaker(request, dispatcher, strict)))
for name, handshaker in handshakers:
_LOGGER.debug('Trying %s protocol', name)
_LOGGER.debug('Trying protocol version %s', name)
try:
handshaker.do_handshake()
_LOGGER.info('Established (%s protocol)', name)

View File

@ -89,7 +89,7 @@ def validate_subprotocol(subprotocol, hixie):
Sec-WebSocket-Protocol.
See
- HyBi 10: Section 5.1. and 5.2.2.
- RFC 6455: Section 4.1., 4.2.2., and 4.3.
- HyBi 00: Section 4.1. Opening handshake
- Hixie 75: Section 4.1. Handshake
"""

View File

@ -28,7 +28,12 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""WebSocket HyBi latest opening handshake processor."""
"""This file provides the opening handshake processor for the WebSocket
protocol (RFC 6455).
Specification:
http://tools.ietf.org/html/rfc6455
"""
# Note: request.connection.write is used in this module, even though mod_python
@ -59,7 +64,10 @@ from mod_pywebsocket.stream import StreamOptions
from mod_pywebsocket import util
_BASE64_REGEX = re.compile('^[+/0-9A-Za-z]*=*$')
# Used to validate the value in the Sec-WebSocket-Key header strictly. RFC 4648
# disallows non-zero padding, so the character right before == must be any of
# A, Q, g and w.
_SEC_WEBSOCKET_KEY_REGEX = re.compile('^[+/0-9A-Za-z]{21}[AQgw]==$')
# Defining aliases for values used frequently.
_VERSION_HYBI08 = common.VERSION_HYBI08
@ -85,7 +93,7 @@ def compute_accept(key):
class Handshaker(object):
"""This class performs WebSocket handshake."""
"""Opening handshake processor for the WebSocket protocol (RFC 6455)."""
def __init__(self, request, dispatcher):
"""Construct an instance.
@ -161,7 +169,7 @@ class Handshaker(object):
accept,
util.hexify(accept_binary))
self._logger.debug('IETF HyBi protocol')
self._logger.debug('Protocol version is RFC 6455')
# Setup extension processors.
@ -258,7 +266,6 @@ class Handshaker(object):
def _set_protocol(self):
self._request.ws_protocol = None
# MOZILLA
self._request.sts = None
# /MOZILLA
@ -307,7 +314,7 @@ class Handshaker(object):
# module. Because base64 module skips invalid characters, we have
# to do this in advance to make this server strictly reject illegal
# keys.
if _BASE64_REGEX.match(key):
if _SEC_WEBSOCKET_KEY_REGEX.match(key):
decoded_key = base64.b64decode(key)
if len(decoded_key) == 16:
key_is_valid = True

View File

@ -28,7 +28,12 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""WebSocket initial handshake hander for HyBi 00 protocol."""
"""This file provides the opening handshake processor for the WebSocket
protocol version HyBi 00.
Specification:
http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
"""
# Note: request.connection.write/read are used in this module, even though
@ -61,7 +66,8 @@ _MANDATORY_HEADERS = [
class Handshaker(object):
"""This class performs WebSocket handshake."""
"""Opening handshake processor for the WebSocket protocol version HyBi 00.
"""
def __init__(self, request, dispatcher):
"""Construct an instance.
@ -139,7 +145,7 @@ class Handshaker(object):
(common.SEC_WEBSOCKET_DRAFT_HEADER,
draft))
self._logger.debug('IETF HyBi 00 protocol')
self._logger.debug('Protocol version is HyBi 00')
self._request.ws_version = common.VERSION_HYBI00
self._request.ws_stream = StreamHixie75(self._request, True)

View File

@ -82,7 +82,15 @@ def receive_message(request):
Args:
request: mod_python request.
Raises:
BadOperationException: when client already terminated.
InvalidFrameException: when client send invalid frame.
UnsupportedFrameException: when client send unsupported frame e.g. some
of reserved bit is set but no extension can
recognize it.
InvalidUTF8Exception: when client send a text frame containing any
invalid UTF-8 string.
ConnectionTerminatedException: when the connection is closed
unexpectedly.
BadOperationException: when client already terminated.
"""
return request.ws_stream.receive_message()

View File

@ -177,9 +177,16 @@ class RepeatedXorMasker(object):
def mask(self, s):
result = array.array('B')
result.fromstring(s)
# Use temporary local variables to eliminate the cost to access
# attributes
count = self._count
mask = self._mask
mask_size = self._mask_size
for i in xrange(len(result)):
result[i] ^= self._mask[self._count]
self._count = (self._count + 1) % self._mask_size
result[i] ^= mask[count]
count = (count + 1) % mask_size
self._count = count
return result.tostring()

View File

@ -32,6 +32,8 @@
"""Standalone WebSocket server.
BASIC USAGE
Use this server to run mod_pywebsocket without Apache HTTP Server.
Usage:
@ -52,11 +54,39 @@ handlers. If this path is relative, <document_root> is used as the base.
<scan_dir> is a path under the root directory. If specified, only the
handlers under scan_dir are scanned. This is useful in saving scan time.
Note:
CONFIGURATION FILE
You can also write a configuration file and use it by specifying the path to
the configuration file by --config option. Please write a configuration file
following the documentation of the Python ConfigParser library. Name of each
entry must be the long version argument name. E.g. to set log level to debug,
add the following line:
log_level=debug
For options which doesn't take value, please add some fake value. E.g. for
--tls option, add the following line:
tls=True
Note that tls will be enabled even if you write tls=False as the value part is
fake.
When both a command line argument and a configuration file entry are set for
the same configuration item, the command line value will override one in the
configuration file.
THREADING
This server is derived from SocketServer.ThreadingMixIn. Hence a thread is
used for each request.
SECURITY WARNING: This uses CGIHTTPServer and CGIHTTPServer is not secure.
SECURITY WARNING
This uses CGIHTTPServer and CGIHTTPServer is not secure.
It may execute arbitrary Python code or external programs. It should not be
used outside a firewall.
"""
@ -65,6 +95,7 @@ import BaseHTTPServer
import CGIHTTPServer
import SimpleHTTPServer
import SocketServer
import ConfigParser
import httplib
import logging
import logging.handlers
@ -77,13 +108,17 @@ import sys
import threading
import time
_HAS_SSL = False
_HAS_OPEN_SSL = False
try:
import OpenSSL.SSL
_HAS_OPEN_SSL = True
import ssl
_HAS_SSL = True
except ImportError:
pass
try:
import OpenSSL.SSL
_HAS_OPEN_SSL = True
except ImportError:
pass
from mod_pywebsocket import common
from mod_pywebsocket import dispatch
@ -193,6 +228,28 @@ class _StandaloneRequest(object):
'Drained data following close frame: %r', drained_data)
class _StandaloneSSLConnection(object):
"""A wrapper class for OpenSSL.SSL.Connection to provide makefile method
which is not supported by the class.
"""
def __init__(self, connection):
self._connection = connection
def __getattribute__(self, name):
if name in ('_connection', 'makefile'):
return object.__getattribute__(self, name)
return self._connection.__getattribute__(name)
def __setattr__(self, name, value):
if name in ('_connection', 'makefile'):
return object.__setattr__(self, name, value)
return self._connection.__setattr__(name, value)
def makefile(self, mode='r', bufsize=-1):
return socket._fileobject(self._connection, mode, bufsize)
class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
"""HTTPServer specialized for WebSocket."""
@ -253,12 +310,18 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
self._logger.info('Skip by failure: %r', e)
continue
if self.websocket_server_options.use_tls:
ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
ctx.use_privatekey_file(
self.websocket_server_options.private_key)
ctx.use_certificate_file(
self.websocket_server_options.certificate)
socket_ = OpenSSL.SSL.Connection(ctx, socket_)
if _HAS_SSL:
socket_ = ssl.wrap_socket(socket_,
keyfile=self.websocket_server_options.private_key,
certfile=self.websocket_server_options.certificate,
ssl_version=ssl.PROTOCOL_SSLv23)
if _HAS_OPEN_SSL:
ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
ctx.use_privatekey_file(
self.websocket_server_options.private_key)
ctx.use_certificate_file(
self.websocket_server_options.certificate)
socket_ = OpenSSL.SSL.Connection(ctx, socket_)
self._sockets.append((socket_, addrinfo))
def server_bind(self):
@ -328,6 +391,18 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
util.get_stack_trace())
# Note: client_address is a tuple.
def get_request(self):
"""Override TCPServer.get_request to wrap OpenSSL.SSL.Connection
object with _StandaloneSSLConnection to provide makefile method. We
cannot substitute OpenSSL.SSL.Connection.makefile since it's readonly
attribute.
"""
accepted_socket, client_address = self.socket.accept()
if self.websocket_server_options.use_tls and _HAS_OPEN_SSL:
accepted_socket = _StandaloneSSLConnection(accepted_socket)
return accepted_socket, client_address
def serve_forever(self, poll_interval=0.5):
"""Override SocketServer.BaseServer.serve_forever."""
@ -413,7 +488,9 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
# it needs variables set by CGIHTTPRequestHandler.parse_request.
#
# Variables set by this method will be also used by WebSocket request
# handling. See _StandaloneRequest.get_request, etc.
# handling (self.path, self.command, self.requestline, etc. See also
# how _StandaloneRequest's members are implemented using these
# attributes).
if not CGIHTTPServer.CGIHTTPRequestHandler.parse_request(self):
return False
host, port, resource = http_header_util.parse_uri(self.path)
@ -567,6 +644,11 @@ def _alias_handlers(dispatcher, websock_handlers_map_file):
def _build_option_parser():
parser = optparse.OptionParser()
parser.add_option('--config', dest='config_file', type='string',
default=None,
help=('Path to configuration file. See the file comment '
'at the top of this file for the configuration '
'file format'))
parser.add_option('-H', '--server-host', '--server_host',
dest='server_host',
default='',
@ -676,14 +758,46 @@ class ThreadMonitor(threading.Thread):
time.sleep(self._interval_in_sec)
def _main(args=None):
def _parse_args_and_config(args):
parser = _build_option_parser()
options, args = parser.parse_args(args=args)
if args:
logging.critical('Unrecognized positional arguments: %r', args)
# First, parse options without configuration file.
temporary_options, temporary_args = parser.parse_args(args=args)
if temporary_args:
logging.critical(
'Unrecognized positional arguments: %r', temporary_args)
sys.exit(1)
if temporary_options.config_file:
try:
config_fp = open(temporary_options.config_file, 'r')
except IOError, e:
logging.critical(
'Failed to open configuration file %r: %r',
temporary_options.config_file,
e)
sys.exit(1)
config_parser = ConfigParser.SafeConfigParser()
config_parser.readfp(config_fp)
config_fp.close()
args_from_config = []
for name, value in config_parser.items('pywebsocket'):
args_from_config.append('--' + name)
args_from_config.append(value)
if args is None:
args = args_from_config
else:
args = args_from_config + args
return parser.parse_args(args=args)
else:
return temporary_options, temporary_args
def _main(args=None):
options, args = _parse_args_and_config(args=args)
os.chdir(options.document_root)
_configure_logging(options)
@ -710,8 +824,8 @@ def _main(args=None):
options.is_executable_method = __check_script
if options.use_tls:
if not _HAS_OPEN_SSL:
logging.critical('To use TLS, install pyOpenSSL.')
if not (_HAS_SSL or _HAS_OPEN_SSL):
logging.critical('TLS support requires ssl or pyOpenSSL.')
sys.exit(1)
if not options.private_key or not options.certificate:
logging.critical(
@ -750,7 +864,7 @@ def _main(args=None):
if __name__ == '__main__':
_main()
_main(sys.argv[1:])
# vi:sts=4 sw=4 et

View File

@ -78,3 +78,5 @@ endif
TEST_DIRS += test
include $(topsrcdir)/config/rules.mk
CXXFLAGS += $(TK_CFLAGS)

View File

@ -87,6 +87,10 @@
#include "AndroidBridge.h"
#endif
#ifdef MOZ_WIDGET_GTK2
#include <gtk/gtk.h>
#endif
using namespace mozilla;
#define DOWNLOAD_MANAGER_BUNDLE "chrome://mozapps/locale/downloads/downloads.properties"
@ -131,6 +135,9 @@ nsDownloadManager::GetSingleton()
gDownloadManagerService = new nsDownloadManager();
if (gDownloadManagerService) {
#if defined(MOZ_WIDGET_GTK2)
g_type_init();
#endif
NS_ADDREF(gDownloadManagerService);
if (NS_FAILED(gDownloadManagerService->Init()))
NS_RELEASE(gDownloadManagerService);
@ -2299,7 +2306,7 @@ nsDownload::SetState(DownloadState aState)
}
}
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK2)
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mTarget);
nsCOMPtr<nsIFile> file;
nsAutoString path;
@ -2309,8 +2316,8 @@ nsDownload::SetState(DownloadState aState)
file &&
NS_SUCCEEDED(file->GetPath(path))) {
#ifdef XP_WIN
// On windows, add the download to the system's "recent documents"
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK2)
// On Windows and Gtk, add the download to the system's "recent documents"
// list, with a pref to disable.
{
bool addToRecentDocs = true;
@ -2319,7 +2326,18 @@ nsDownload::SetState(DownloadState aState)
if (addToRecentDocs &&
!nsDownloadManager::gDownloadManagerService->mInPrivateBrowsing) {
#ifdef XP_WIN
::SHAddToRecentDocs(SHARD_PATHW, path.get());
#elif defined(MOZ_WIDGET_GTK2)
GtkRecentManager* manager = gtk_recent_manager_get_default();
gchar* uri = g_filename_to_uri(NS_ConvertUTF16toUTF8(path).get(),
NULL, NULL);
if (uri) {
gtk_recent_manager_add_item(manager, uri);
g_free(uri);
}
#endif
}
}
#endif

View File

@ -57,7 +57,7 @@
<binding id="label-control" extends="chrome://global/content/bindings/text.xml#text-label">
<content>
<html:span anonid="accessKeyParens"><children/></html:span>
<children/><html:span anonid="accessKeyParens"></html:span>
</content>
<implementation implements="nsIDOMXULLabelElement">
<constructor>
@ -106,7 +106,7 @@
}
var afterLabel = document.getAnonymousElementByAttribute(this, "anonid", "accessKeyParens");
afterLabel.textContent = ""; // This does not clear real nodes!
afterLabel.textContent = "";
var oldAccessKey = this.getElementsByAttribute('class', 'accesskey').item(0);
if (oldAccessKey) { // Clear old accesskey

View File

@ -409,6 +409,7 @@ var gCheckUpdateSecurityDefault = true;
var gCheckUpdateSecurity = gCheckUpdateSecurityDefault;
var gUpdateEnabled = true;
var gAutoUpdateDefault = true;
var gHotfixID = null;
/**
* This is the real manager, kept here rather than in AddonManager to keep its
@ -538,6 +539,11 @@ var AddonManagerInternal = {
} catch (e) {}
Services.prefs.addObserver(PREF_EM_AUTOUPDATE_DEFAULT, this, false);
try {
gHotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID);
} catch (e) {}
Services.prefs.addObserver(PREF_EM_HOTFIX_ID, this, false);
// Ensure all default providers have had a chance to register themselves
DEFAULT_PROVIDERS.forEach(function(url) {
try {
@ -664,6 +670,7 @@ var AddonManagerInternal = {
Services.prefs.removeObserver(PREF_EM_CHECK_UPDATE_SECURITY, this);
Services.prefs.removeObserver(PREF_EM_UPDATE_ENABLED, this);
Services.prefs.removeObserver(PREF_EM_AUTOUPDATE_DEFAULT, this);
Services.prefs.removeObserver(PREF_EM_HOTFIX_ID, this);
this.providers.forEach(function(provider) {
callProvider(provider, "shutdown");
@ -752,6 +759,14 @@ var AddonManagerInternal = {
this.callManagerListeners("onUpdateModeChanged");
break;
}
case PREF_EM_HOTFIX_ID: {
try {
gHotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID);
} catch(e) {
gHotfixID = null;
}
break;
}
}
},
@ -825,9 +840,7 @@ var AddonManagerInternal = {
* that can be updated.
*/
backgroundUpdateCheck: function AMI_backgroundUpdateCheck() {
let hotfixID = null;
if (Services.prefs.getPrefType(PREF_EM_HOTFIX_ID) == Ci.nsIPrefBranch.PREF_STRING)
hotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID);
let hotfixID = this.hotfixID;
let checkHotfix = hotfixID &&
Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) &&
@ -1688,7 +1701,11 @@ var AddonManagerInternal = {
if (aValue != gUpdateEnabled)
Services.prefs.setBoolPref(PREF_EM_UPDATE_ENABLED, aValue);
return aValue;
}
},
get hotfixID() {
return gHotfixID;
},
};
/**
@ -2068,6 +2085,10 @@ var AddonManager = {
AddonManagerInternal.autoUpdateDefault = aValue;
},
get hotfixID() {
return AddonManagerInternal.hotfixID;
},
escapeAddonURI: function AM_escapeAddonURI(aAddon, aUri, aAppVersion) {
return AddonManagerInternal.escapeAddonURI(aAddon, aUri, aAppVersion);
}

View File

@ -2672,7 +2672,7 @@ var gDetailView = {
downloadsRow.value = null;
}
var canUpdate = !aIsRemote && hasPermission(aAddon, "upgrade");
var canUpdate = !aIsRemote && hasPermission(aAddon, "upgrade") && aAddon.id != AddonManager.hotfixID;
document.getElementById("detail-updates-row").hidden = !canUpdate;
if ("applyBackgroundUpdates" in aAddon) {

View File

@ -7,6 +7,7 @@
const PREF_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault"
const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
const SEARCH_URL = TESTROOT + "browser_details.xml";
const PREF_EM_HOTFIX_ID = "extensions.hotfix.id";
var gManagerWindow;
var gCategoryUtilities;
@ -47,6 +48,7 @@ function test() {
// Turn on searching for this test
Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
Services.prefs.setCharPref(PREF_GETADDONS_GETSEARCHRESULTS, SEARCH_URL);
Services.prefs.setCharPref(PREF_EM_HOTFIX_ID, "hotfix@tests.mozilla.org");
waitForExplicitFinish();
@ -141,6 +143,9 @@ function test() {
blocklistURL: "http://example.com/addon8@tests.mozilla.org",
name: "Test add-on 8",
blocklistState: Ci.nsIBlocklistService.STATE_OUTDATED
}, {
id: "hotfix@tests.mozilla.org",
name: "Test hotfix 1",
}]);
open_manager(null, function(aWindow) {
@ -152,6 +157,7 @@ function test() {
}
function end_test() {
Services.prefs.clearUserPref(PREF_EM_HOTFIX_ID);
close_manager(gManagerWindow, function() {
finish();
});
@ -175,6 +181,7 @@ add_test(function() {
is_element_visible(get("detail-contrib-suggested"), "Contributions amount should be visible");
ok(get("detail-contrib-suggested").value, "$0.99");
is_element_visible(get("detail-updates-row"), "Updates should not be hidden");
is_element_hidden(get("detail-dateUpdated"), "Update date should be hidden");
is_element_visible(get("detail-rating-row"), "Rating row should not be hidden");
@ -336,6 +343,7 @@ add_test(function() {
is_element_hidden(get("detail-contributions"), "Contributions section should be hidden");
is_element_visible(get("detail-updates-row"), "Updates should not be hidden");
is_element_visible(get("detail-dateUpdated"), "Update date should not be hidden");
is(get("detail-dateUpdated").value, formatDate(gDate), "Update date should be correct");
@ -678,6 +686,26 @@ add_test(function() {
});
});
// Opens and tests the details view for hotfix 1
add_test(function() {
open_details("hotfix@tests.mozilla.org", "extension", function() {
is(get("detail-name").textContent, "Test hotfix 1", "Name should be correct");
is_element_hidden(get("detail-updates-row"), "Updates should be hidden");
is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
is_element_hidden(get("detail-warning"), "Warning message should be hidden");
is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
is_element_hidden(get("detail-pending"), "Pending message should be hidden");
run_next_test();
});
});
// Tests that upgrades with onExternalInstall apply immediately
add_test(function() {
open_details("addon1@tests.mozilla.org", "extension", function() {

View File

@ -205,6 +205,21 @@ function run_test() {
gManagerEventsListener.shutdown();
// AddonManager.hotfixID
let hotfixID = "hotfix@tests.mozilla.org";
Services.prefs.setCharPref("extensions.hotfix.id", hotfixID);
do_check_eq(AddonManager.hotfixID, hotfixID);
// Change the pref and make sure the property is updated
hotfixID = "hotfix2@tests.mozilla.org";
Services.prefs.setCharPref("extensions.hotfix.id", hotfixID);
do_check_eq(AddonManager.hotfixID, hotfixID);
// Test an invalid pref value
hotfixID = 99;
Services.prefs.deleteBranch("extensions.hotfix.id");
Services.prefs.setIntPref("extensions.hotfix.id", hotfixID);
do_check_eq(AddonManager.hotfixID, null);
Services.prefs.clearUserPref("extensions.hotfix.id");
// After removing the listener, ensure we get no further events.
gManagerEventsListener.expect([]);
AddonManager.updateEnabled = false;

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