merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-10-09 11:43:07 +02:00
commit 13543931d2
185 changed files with 3545 additions and 1332 deletions

View File

@ -0,0 +1,19 @@
MOZ_AUTOMATION_BUILD_SYMBOLS=0
MOZ_AUTOMATION_PACKAGE_TESTS=0
MOZ_AUTOMATION_L10N_CHECK=0
. $topsrcdir/build/macosx/mozconfig.common
ac_add_options --disable-debug
ac_add_options --enable-optimize
ac_add_options --enable-dmd
# Treat warnings as errors (modulo ALLOW_COMPILER_WARNINGS).
ac_add_options --enable-warnings-as-errors
ac_add_options --enable-clang-plugin
. "$topsrcdir/build/macosx/mozconfig.rust"
. "$topsrcdir/build/mozconfig.common.override"
. "$topsrcdir/build/mozconfig.cache"

View File

@ -6,7 +6,7 @@
"size": 93197192,
"digest": "6ebd8994ac76cf6694c3d9054104219836f47578223c799cb9ba9669cfdee00112e9de56aea9d1e6d9d50ee94a201970555de19794b5fbb7546f58fdf8e59a99",
"algorithm": "sha512",
"filename": "clang.tar.bz2",
"filename": "clang.tar.xz",
"unpack": true,
}
]

View File

@ -6,7 +6,7 @@
"size": 97314461,
"digest": "9a74670fa917f760a4767923485d5166bbd258a8023c8aeb899b8c4d22f2847be76508ac5f26d7d2193318a2bb368a71bc62888d1bfe9d81eb45329a60451aa4",
"algorithm": "sha512",
"filename": "clang.tar.xz",
"filename": "clang.tar.bz2",
"unpack": true
},
{

View File

@ -66,15 +66,37 @@ public class CodeGenerator {
return (includeScope ? clsName + "::" : "") + uniqueName + "_t";
}
/**
* Return the C++ type name for this class or any class within the chain
* of declaring classes, if the target class matches the given type.
*
* Return null if the given type does not match any class searched.
*/
private String getMatchingClassType(final Class<?> type) {
Class<?> cls = this.cls;
String clsName = this.clsName;
while (cls != null) {
if (type == cls) {
return clsName;
}
cls = cls.getDeclaringClass();
clsName = clsName.substring(0, Math.max(0, clsName.lastIndexOf("::")));
}
return null;
}
private String getNativeParameterType(Class<?> type, AnnotationInfo info) {
if (type == cls) {
final String clsName = getMatchingClassType(type);
if (clsName != null) {
return Utils.getUnqualifiedName(clsName) + "::Param";
}
return Utils.getNativeParameterType(type, info);
}
private String getNativeReturnType(Class<?> type, AnnotationInfo info) {
if (type == cls) {
final String clsName = getMatchingClassType(type);
if (clsName != null) {
return Utils.getUnqualifiedName(clsName) + "::LocalRef";
}
return Utils.getNativeReturnType(type, info);
@ -370,6 +392,7 @@ public class CodeGenerator {
if (isStatic && isFinal && (type.isPrimitive() || type == String.class)) {
Object val = null;
try {
field.setAccessible(true);
val = field.get(null);
} catch (final IllegalAccessException e) {
}

View File

@ -64,7 +64,7 @@ def updated_env(env):
def build_tar_package(tar, name, base, directory):
name = os.path.realpath(name)
run_in(base, [tar,
"-c -%s -f" % "J" if ".xz" in name else "j",
"-c -%s -f" % ("J" if ".xz" in name else "j"),
name, directory])

View File

@ -55,16 +55,17 @@ function* basicTest() {
}
function* overrideTest() {
let gradientText = "(45deg, rgba(255,255,255,0.2) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.2) 75%, transparent 75%, transparent);";
let gradientText1 = "(orange, blue);";
let gradientText2 = "(pink, teal);";
let view =
yield createTestContent("#testid {" +
" background-image: -moz-linear-gradient" +
gradientText +
" background-image: -webkit-linear-gradient" +
gradientText +
" background-image: linear-gradient" +
gradientText +
gradientText1 +
" background-image: -ms-linear-gradient" +
gradientText2 +
" background-image: linear-gradient" +
gradientText2 +
"} ");
let elementStyle = view._elementStyle;

View File

@ -4106,11 +4106,6 @@ this.DOMApplicationRegistry = {
},
doUninstall: Task.async(function*(aData, aMm) {
// The yields here could get stuck forever, so we only hold
// a weak reference to the message manager while yielding, to avoid
// leaking the whole page associationed with the message manager.
aMm = Cu.getWeakReference(aMm);
let response = "Webapps:Uninstall:Return:OK";
try {
@ -4140,9 +4135,7 @@ this.DOMApplicationRegistry = {
response = "Webapps:Uninstall:Return:KO";
}
if ((aMm = aMm.get())) {
aMm.sendAsyncMessage(response, this.formatMessage(aData));
}
aMm.sendAsyncMessage(response, this.formatMessage(aData));
}),
uninstall: function(aManifestURL) {

View File

@ -114,9 +114,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(EventSource,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadGroup)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHttpChannel)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnicodeDecoder)
@ -490,48 +488,6 @@ EventSource::OnStopRequest(nsIRequest *aRequest,
return NS_OK;
}
/**
* Simple helper class that just forwards the redirect callback back
* to the EventSource.
*/
class AsyncVerifyRedirectCallbackFwr final : public nsIAsyncVerifyRedirectCallback
{
public:
explicit AsyncVerifyRedirectCallbackFwr(EventSource* aEventsource)
: mEventSource(aEventsource)
{
}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(AsyncVerifyRedirectCallbackFwr)
// nsIAsyncVerifyRedirectCallback implementation
NS_IMETHOD OnRedirectVerifyCallback(nsresult aResult) override
{
nsresult rv = mEventSource->OnRedirectVerifyCallback(aResult);
if (NS_FAILED(rv)) {
mEventSource->mErrorLoadOnRedirect = true;
mEventSource->DispatchFailConnection();
}
return NS_OK;
}
private:
~AsyncVerifyRedirectCallbackFwr() {}
nsRefPtr<EventSource> mEventSource;
};
NS_IMPL_CYCLE_COLLECTION(AsyncVerifyRedirectCallbackFwr, mEventSource)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AsyncVerifyRedirectCallbackFwr)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(AsyncVerifyRedirectCallbackFwr)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AsyncVerifyRedirectCallbackFwr)
//-----------------------------------------------------------------------------
// EventSource::nsIChannelEventSink
//-----------------------------------------------------------------------------
@ -564,56 +520,20 @@ EventSource::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
return NS_ERROR_DOM_SECURITY_ERR;
}
// Prepare to receive callback
mRedirectFlags = aFlags;
mRedirectCallback = aCallback;
mNewRedirectChannel = aNewChannel;
if (mChannelEventSink) {
nsRefPtr<AsyncVerifyRedirectCallbackFwr> fwd =
new AsyncVerifyRedirectCallbackFwr(this);
rv = mChannelEventSink->AsyncOnChannelRedirect(aOldChannel,
aNewChannel,
aFlags, fwd);
if (NS_FAILED(rv)) {
mRedirectCallback = nullptr;
mNewRedirectChannel = nullptr;
mErrorLoadOnRedirect = true;
DispatchFailConnection();
}
return rv;
}
OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
nsresult
EventSource::OnRedirectVerifyCallback(nsresult aResult)
{
MOZ_ASSERT(mRedirectCallback, "mRedirectCallback not set in callback");
MOZ_ASSERT(mNewRedirectChannel,
"mNewRedirectChannel not set in callback");
NS_ENSURE_SUCCESS(aResult, aResult);
// update our channel
mHttpChannel = do_QueryInterface(mNewRedirectChannel);
mHttpChannel = do_QueryInterface(aNewChannel);
NS_ENSURE_STATE(mHttpChannel);
nsresult rv = SetupHttpChannel();
rv = SetupHttpChannel();
NS_ENSURE_SUCCESS(rv, rv);
if ((mRedirectFlags & nsIChannelEventSink::REDIRECT_PERMANENT) != 0) {
if ((aFlags & nsIChannelEventSink::REDIRECT_PERMANENT) != 0) {
rv = NS_GetFinalChannelURI(mHttpChannel, getter_AddRefs(mSrc));
NS_ENSURE_SUCCESS(rv, rv);
}
mNewRedirectChannel = nullptr;
mRedirectCallback->OnRedirectVerifyCallback(aResult);
mRedirectCallback = nullptr;
aCallback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
@ -626,27 +546,12 @@ NS_IMETHODIMP
EventSource::GetInterface(const nsIID & aIID,
void **aResult)
{
// Make sure to return ourselves for the channel event sink interface,
// no matter what. We can forward these to mNotificationCallbacks
// if it wants to get notifications for them. But we
// need to see these notifications for proper functioning.
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
mChannelEventSink = do_GetInterface(mNotificationCallbacks);
*aResult = static_cast<nsIChannelEventSink*>(this);
NS_ADDREF_THIS();
return NS_OK;
}
// Now give mNotificationCallbacks (if non-null) a chance to return the
// desired interface.
if (mNotificationCallbacks) {
nsresult rv = mNotificationCallbacks->GetInterface(aIID, aResult);
if (NS_SUCCEEDED(rv)) {
NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!");
return rv;
}
}
if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
nsresult rv = CheckInnerWindowCorrectness();
@ -807,12 +712,14 @@ EventSource::InitChannelAndRequestEventSource()
rv = SetupHttpChannel();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
if (notificationCallbacks != this) {
mNotificationCallbacks = notificationCallbacks;
mHttpChannel->SetNotificationCallbacks(this);
#ifdef DEBUG
{
nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
MOZ_ASSERT(!notificationCallbacks);
}
#endif
mHttpChannel->SetNotificationCallbacks(this);
// Start reading from the channel
rv = mHttpChannel->AsyncOpen2(this);
@ -878,11 +785,7 @@ EventSource::ResetConnection()
mLastConvertionResult = NS_OK;
mHttpChannel = nullptr;
mNotificationCallbacks = nullptr;
mChannelEventSink = nullptr;
mStatus = PARSE_STATE_OFF;
mRedirectCallback = nullptr;
mNewRedirectChannel = nullptr;
mReadyState = CONNECTING;

View File

@ -34,7 +34,6 @@ class ErrorResult;
namespace dom {
class AsyncVerifyRedirectCallbackFwr;
struct EventSourceInit;
class EventSource final : public DOMEventTargetHelper
@ -44,8 +43,6 @@ class EventSource final : public DOMEventTargetHelper
, public nsIInterfaceRequestor
, public nsSupportsWeakReference
{
friend class AsyncVerifyRedirectCallbackFwr;
public:
explicit EventSource(nsPIDOMWindow* aOwnerWindow);
NS_DECL_ISUPPORTS_INHERITED
@ -232,13 +229,6 @@ protected:
nsCOMPtr<nsILoadGroup> mLoadGroup;
/**
* The notification callbacks the channel had initially.
* We want to forward things here as needed.
*/
nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
nsCOMPtr<nsIChannelEventSink> mChannelEventSink;
nsCOMPtr<nsIHttpChannel> mHttpChannel;
nsCOMPtr<nsITimer> mTimer;
@ -249,10 +239,6 @@ protected:
nsCOMPtr<nsIPrincipal> mPrincipal;
nsString mOrigin;
uint32_t mRedirectFlags;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIChannel> mNewRedirectChannel;
// Event Source owner information:
// - the script file name
// - source code line number and column number where the Event Source object

View File

@ -274,13 +274,27 @@ WindowNamedPropertiesHandler::Create(JSContext* aCx,
// Note: since the scope polluter proxy lives on the window's prototype
// chain, it needs a singleton type to avoid polluting type information
// for properties on the window.
JS::Rooted<JSObject*> gsp(aCx);
js::ProxyOptions options;
options.setSingleton(true);
options.setClass(&WindowNamedPropertiesClass.mBase);
return js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
JS::NullHandleValue, aProto,
options);
JS::Rooted<JSObject*> gsp(aCx);
gsp = js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
JS::NullHandleValue, aProto,
options);
if (!gsp) {
return nullptr;
}
bool succeeded;
if (!JS_SetImmutablePrototype(aCx, gsp, &succeeded)) {
return nullptr;
}
MOZ_ASSERT(succeeded,
"errors making the [[Prototype]] of the named properties object "
"immutable should have been JSAPI failures, not !succeeded");
return gsp;
}
} // namespace dom

View File

@ -199,6 +199,49 @@ MessageEvent::InitMessageEvent(const nsAString& aType,
return NS_OK;
}
void
MessageEvent::InitMessageEvent(JSContext* aCx, const nsAString& aType,
bool aCanBubble, bool aCancelable,
JS::Handle<JS::Value> aData,
const nsAString& aOrigin,
const nsAString& aLastEventId,
const Nullable<WindowProxyOrMessagePort>& aSource,
const Nullable<Sequence<OwningNonNull<MessagePort>>>& aPorts,
ErrorResult& aRv)
{
aRv = Event::InitEvent(aType, aCanBubble, aCancelable);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
mData = aData;
mozilla::HoldJSObjects(this);
mOrigin = aOrigin;
mLastEventId = aLastEventId;
mWindowSource = nullptr;
mPortSource = nullptr;
if (!aSource.IsNull()) {
if (aSource.Value().IsWindowProxy()) {
mWindowSource = aSource.Value().GetAsWindowProxy();
} else {
mPortSource = &aSource.Value().GetAsMessagePort();
}
}
mPorts = nullptr;
if (!aPorts.IsNull()) {
nsTArray<nsRefPtr<MessagePort>> ports;
for (uint32_t i = 0, len = aPorts.Value().Length(); i < len; ++i) {
ports.AppendElement(aPorts.Value()[i]);
}
mPorts = new MessagePortList(static_cast<Event*>(this), ports);
}
}
void
MessageEvent::SetPorts(MessagePortList* aPorts)
{
@ -227,7 +270,7 @@ using namespace mozilla::dom;
already_AddRefed<MessageEvent>
NS_NewDOMMessageEvent(EventTarget* aOwner,
nsPresContext* aPresContext,
WidgetEvent* aEvent)
WidgetEvent* aEvent)
{
nsRefPtr<MessageEvent> it = new MessageEvent(aOwner, aPresContext, aEvent);
return it.forget();

View File

@ -8,9 +8,10 @@
#define mozilla_dom_MessageEvent_h_
#include "mozilla/dom/Event.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/MessagePortList.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDOMMessageEvent.h"
#include "mozilla/dom/MessagePortList.h"
namespace mozilla {
namespace dom {
@ -19,6 +20,7 @@ struct MessageEventInit;
class MessagePort;
class MessagePortList;
class OwningWindowProxyOrMessagePortOrClient;
class WindowProxyOrMessagePort;
namespace workers {
@ -85,6 +87,13 @@ public:
const MessageEventInit& aEventInit,
ErrorResult& aRv);
void InitMessageEvent(JSContext* aCx, const nsAString& aType, bool aCanBubble,
bool aCancelable, JS::Handle<JS::Value> aData,
const nsAString& aOrigin, const nsAString& aLastEventId,
const Nullable<WindowProxyOrMessagePort>& aSource,
const Nullable<Sequence<OwningNonNull<MessagePort>>>& aPorts,
ErrorResult& aRv);
protected:
~MessageEvent();

View File

@ -13,6 +13,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=848294
</head>
<body>
<script type="application/javascript">
function testMessageEvent(e, test) {
ok(e, "MessageEvent created");
is(e.type, 'message', 'MessageEvent.type is right');
is(e.data, 'data' in test ? test.data : undefined, 'MessageEvent.data is ok');
is(e.origin, 'origin' in test ? test.origin : '', 'MessageEvent.origin is ok');
is(e.lastEventId, 'lastEventId' in test ? test.lastEventId : '', 'MessageEvent.lastEventId is ok');
is(e.source, 'source' in test ? test.source : null, 'MessageEvent.source is ok');
if (test.ports != undefined) {
is(e.ports.length, test.ports.length, 'MessageEvent.ports is ok');
is(e.ports, e.ports, 'MessageEvent.ports is ok');
} else {
ok(!('ports' in test) || test.ports == null, 'MessageEvent.ports is ok');
}
}
function runTest() {
var channel = new MessageChannel();
@ -33,20 +50,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=848294
var test = tests.shift();
var e = new MessageEvent('message', test);
ok(e, "MessageEvent created");
is(e.type, 'message', 'MessageEvent.type is right');
testMessageEvent(e, test);
is(e.data, 'data' in test ? test.data : undefined, 'MessageEvent.data is ok');
is(e.origin, 'origin' in test ? test.origin : '', 'MessageEvent.origin is ok');
is(e.lastEventId, 'lastEventId' in test ? test.lastEventId : '', 'MessageEvent.lastEventId is ok');
is(e.source, 'source' in test ? test.source : null, 'MessageEvent.source is ok');
if (test.ports != undefined) {
is(e.ports.length, test.ports.length, 'MessageEvent.ports is ok');
is(e.ports, e.ports, 'MessageEvent.ports is ok');
} else {
ok(!('ports' in test) || test.ports == null, 'MessageEvent.ports is ok');
}
e = new MessageEvent('message');
e.initMessageEvent('message', true, true,
'data' in test ? test.data : undefined,
'origin' in test ? test.origin : '',
'lastEventId' in test ? test.lastEventId : '',
'source' in test ? test.source : null,
'ports' in test ? test.ports : null);
testMessageEvent(e, test);
}
try {

View File

@ -7,6 +7,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/FetchDriver.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIDocument.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
@ -42,7 +43,7 @@ namespace dom {
NS_IMPL_ISUPPORTS(FetchDriver,
nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
nsIAsyncVerifyRedirectCallback, nsIThreadRetargetableStreamListener)
nsIThreadRetargetableStreamListener)
FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
nsILoadGroup* aLoadGroup)
@ -459,7 +460,13 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica
// Insert ourselves into the notification callbacks chain so we can handle
// cross-origin redirects.
chan->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
#ifdef DEBUG
{
nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
chan->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
MOZ_ASSERT(!notificationCallbacks);
}
#endif
chan->SetNotificationCallbacks(this);
// FIXME(nsm): Bug 1120715.
@ -915,8 +922,6 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
{
NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
nsresult rv;
// HTTP Fetch step 5, "redirect status", step 1
if (NS_WARN_IF(mRequest->GetRedirectMode() == RequestRedirect::Error)) {
aOldChannel->Cancel(NS_BINDING_FAILED);
@ -970,27 +975,85 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
// to a URL with credentials in CORS mode. This is implemented in
// nsCORSListenerProxy.
mRedirectCallback = aCallback;
mOldRedirectChannel = aOldChannel;
mNewRedirectChannel = aNewChannel;
// On a successful redirect we perform the following substeps of HTTP Fetch,
// step 5, "redirect status", step 11.
nsCOMPtr<nsIChannelEventSink> outer =
do_GetInterface(mNotificationCallbacks);
if (outer) {
// The callee is supposed to call OnRedirectVerifyCallback() on success,
// and nobody has to call it on failure, so we can just return after this
// block.
rv = outer->AsyncOnChannelRedirect(aOldChannel, aNewChannel, aFlags, this);
if (NS_FAILED(rv)) {
aOldChannel->Cancel(rv);
mRedirectCallback = nullptr;
mOldRedirectChannel = nullptr;
mNewRedirectChannel = nullptr;
}
// Step 11.5 "Append locationURL to request's url list." so that when we set the
// Response's URL from the Request's URL in Main Fetch, step 15, we get the
// final value. Note, we still use a single URL value instead of a list.
nsCOMPtr<nsIURI> newURI;
nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
if (NS_FAILED(rv)) {
aOldChannel->Cancel(rv);
return rv;
}
(void) OnRedirectVerifyCallback(NS_OK);
// We need to update our request's URL.
nsAutoCString newUrl;
newURI->GetSpec(newUrl);
mRequest->SetURL(newUrl);
// Implement Main Fetch step 8 again on redirect.
MainFetchOp nextOp = SetTaintingAndGetNextOp(mCORSFlagEverSet);
if (nextOp.mType == NETWORK_ERROR) {
// Cancel the channel if Main Fetch blocks the redirect from continuing.
aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
return NS_ERROR_DOM_BAD_URI;
}
// Otherwise, we rely on necko and the CORS proxy to do the right thing
// as the redirect is followed. In general this means basic or http
// fetch. If we've ever been CORS, we need to stay CORS.
MOZ_ASSERT(nextOp.mType == BASIC_FETCH || nextOp.mType == HTTP_FETCH);
MOZ_ASSERT_IF(mCORSFlagEverSet, nextOp.mType == HTTP_FETCH);
MOZ_ASSERT_IF(mCORSFlagEverSet, nextOp.mCORSFlag);
// Examine and possibly set the LOAD_ANONYMOUS flag on the channel.
nsLoadFlags flags;
rv = aNewChannel->GetLoadFlags(&flags);
if (NS_FAILED(rv)) {
aOldChannel->Cancel(rv);
return rv;
}
if (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin &&
mRequest->GetResponseTainting() == InternalRequest::RESPONSETAINT_OPAQUE) {
// In the case of a "no-cors" mode request with "same-origin" credentials,
// we have to set LOAD_ANONYMOUS manually here in order to avoid sending
// credentials on a cross-origin redirect.
flags |= nsIRequest::LOAD_ANONYMOUS;
rv = aNewChannel->SetLoadFlags(flags);
if (NS_FAILED(rv)) {
aOldChannel->Cancel(rv);
return rv;
}
} else if (mRequest->GetCredentialsMode() == RequestCredentials::Omit) {
// Make sure nothing in the redirect chain screws up our credentials
// settings. LOAD_ANONYMOUS must be set if we RequestCredentials is "omit".
MOZ_ASSERT(flags & nsIRequest::LOAD_ANONYMOUS);
} else if (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin &&
nextOp.mCORSFlag) {
// We also want to verify the LOAD_ANONYMOUS flag is set when we are in
// "same-origin" credentials mode and the CORS flag is set. We can't
// unconditionally assert here, however, because the nsCORSListenerProxy
// will set the flag later in the redirect callback chain. Instead,
// perform a weaker assertion here by checking if CORS flag was set
// before this redirect. In that case LOAD_ANONYMOUS must still be set.
MOZ_ASSERT_IF(mCORSFlagEverSet, flags & nsIRequest::LOAD_ANONYMOUS);
} else {
// Otherwise, we should be sending credentials
MOZ_ASSERT(!(flags & nsIRequest::LOAD_ANONYMOUS));
}
// Track the CORSFlag through redirects.
mCORSFlagEverSet = mCORSFlagEverSet || nextOp.mCORSFlag;
aCallback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
@ -1036,21 +1099,12 @@ FetchDriver::GetInterface(const nsIID& aIID, void **aResult)
return NS_OK;
}
nsresult rv;
if (mNotificationCallbacks) {
rv = mNotificationCallbacks->GetInterface(aIID, aResult);
if (NS_SUCCEEDED(rv)) {
NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!");
return rv;
}
}
else if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
*aResult = static_cast<nsIStreamListener*>(this);
NS_ADDREF_THIS();
return NS_OK;
}
else if (aIID.Equals(NS_GET_IID(nsIRequestObserver))) {
if (aIID.Equals(NS_GET_IID(nsIRequestObserver))) {
*aResult = static_cast<nsIRequestObserver*>(this);
NS_ADDREF_THIS();
return NS_OK;
@ -1059,90 +1113,6 @@ FetchDriver::GetInterface(const nsIID& aIID, void **aResult)
return QueryInterface(aIID, aResult);
}
NS_IMETHODIMP
FetchDriver::OnRedirectVerifyCallback(nsresult aResult)
{
// On a successful redirect we perform the following substeps of HTTP Fetch,
// step 5, "redirect status", step 11.
if (NS_SUCCEEDED(aResult)) {
// Step 11.5 "Append locationURL to request's url list." so that when we set the
// Response's URL from the Request's URL in Main Fetch, step 15, we get the
// final value. Note, we still use a single URL value instead of a list.
nsCOMPtr<nsIURI> newURI;
nsresult rv = NS_GetFinalChannelURI(mNewRedirectChannel, getter_AddRefs(newURI));
if (NS_WARN_IF(NS_FAILED(rv))) {
aResult = rv;
} else {
// We need to update our request's URL.
nsAutoCString newUrl;
newURI->GetSpec(newUrl);
mRequest->SetURL(newUrl);
}
}
if (NS_FAILED(aResult)) {
mOldRedirectChannel->Cancel(aResult);
}
// Implement Main Fetch step 8 again on redirect.
MainFetchOp nextOp = SetTaintingAndGetNextOp(mCORSFlagEverSet);
if (nextOp.mType == NETWORK_ERROR) {
// Cancel the channel if Main Fetch blocks the redirect from continuing.
aResult = NS_ERROR_DOM_BAD_URI;
mOldRedirectChannel->Cancel(aResult);
} else {
// Otherwise, we rely on necko and the CORS proxy to do the right thing
// as the redirect is followed. In general this means basic or http
// fetch. If we've ever been CORS, we need to stay CORS.
MOZ_ASSERT(nextOp.mType == BASIC_FETCH || nextOp.mType == HTTP_FETCH);
MOZ_ASSERT_IF(mCORSFlagEverSet, nextOp.mType == HTTP_FETCH);
MOZ_ASSERT_IF(mCORSFlagEverSet, nextOp.mCORSFlag);
// Examine and possibly set the LOAD_ANONYMOUS flag on the channel.
nsLoadFlags flags;
aResult = mNewRedirectChannel->GetLoadFlags(&flags);
if (NS_SUCCEEDED(aResult)) {
if (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin &&
mRequest->GetResponseTainting() == InternalRequest::RESPONSETAINT_OPAQUE) {
// In the case of a "no-cors" mode request with "same-origin" credentials,
// we have to set LOAD_ANONYMOUS manually here in order to avoid sending
// credentials on a cross-origin redirect.
flags |= nsIRequest::LOAD_ANONYMOUS;
aResult = mNewRedirectChannel->SetLoadFlags(flags);
} else if (mRequest->GetCredentialsMode() == RequestCredentials::Omit) {
// Make sure nothing in the redirect chain screws up our credentials
// settings. LOAD_ANONYMOUS must be set if we RequestCredentials is "omit".
MOZ_ASSERT(flags & nsIRequest::LOAD_ANONYMOUS);
} else if (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin &&
nextOp.mCORSFlag) {
// We also want to verify the LOAD_ANONYMOUS flag is set when we are in
// "same-origin" credentials mode and the CORS flag is set. We can't
// unconditionally assert here, however, because the nsCORSListenerProxy
// will set the flag later in the redirect callback chain. Instead,
// perform a weaker assertion here by checking if CORS flag was set
// before this redirect. In that case LOAD_ANONYMOUS must still be set.
MOZ_ASSERT_IF(mCORSFlagEverSet, flags & nsIRequest::LOAD_ANONYMOUS);
} else {
// Otherwise, we should be sending credentials
MOZ_ASSERT(!(flags & nsIRequest::LOAD_ANONYMOUS));
}
}
// Track the CORSFlag through redirects.
mCORSFlagEverSet = mCORSFlagEverSet || nextOp.mCORSFlag;
}
mOldRedirectChannel = nullptr;
mNewRedirectChannel = nullptr;
mRedirectCallback->OnRedirectVerifyCallback(aResult);
mRedirectCallback = nullptr;
return NS_OK;
}
void
FetchDriver::SetDocument(nsIDocument* aDocument)
{

View File

@ -8,7 +8,6 @@
#define mozilla_dom_FetchDriver_h
#include "nsAutoPtr.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIChannelEventSink.h"
#include "nsIInterfaceRequestor.h"
#include "nsIStreamListener.h"
@ -58,7 +57,6 @@ private:
class FetchDriver final : public nsIStreamListener,
public nsIChannelEventSink,
public nsIInterfaceRequestor,
public nsIAsyncVerifyRedirectCallback,
public nsIThreadRetargetableStreamListener
{
public:
@ -67,7 +65,6 @@ public:
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSICHANNELEVENTSINK
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
@ -84,10 +81,6 @@ private:
nsRefPtr<InternalResponse> mResponse;
nsCOMPtr<nsIOutputStream> mPipeOutputStream;
nsRefPtr<FetchDriverObserver> mObserver;
nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIChannel> mOldRedirectChannel;
nsCOMPtr<nsIChannel> mNewRedirectChannel;
nsCOMPtr<nsIDocument> mDocument;
uint32_t mFetchRecursionCount;
bool mCORSFlagEverSet;

View File

@ -1443,6 +1443,7 @@ TabParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
a11y::DocAccessibleParent*
TabParent::GetTopLevelDocAccessible() const
{
#ifdef ACCESSIBILITY
// XXX Consider managing non top level PDocAccessibles with their parent
// document accessible.
const nsTArray<PDocAccessibleParent*>& docs = ManagedPDocAccessibleParent();
@ -1453,7 +1454,7 @@ TabParent::GetTopLevelDocAccessible() const
return doc;
}
}
#endif
return nullptr;
}

View File

@ -39,9 +39,9 @@ class nsIDocShell;
namespace mozilla {
namespace a11y {
namespace a11y {
class DocAccessibleParent;
}
}
namespace jsipc {
class CpowHolder;
@ -266,7 +266,7 @@ public:
/**
* Return the top level doc accessible parent for this tab.
*/
a11y::DocAccessibleParent* GetTopLevelDocAccessible() const;
a11y::DocAccessibleParent* GetTopLevelDocAccessible() const;
void LoadURL(nsIURI* aURI);
// XXX/cjones: it's not clear what we gain by hiding these

View File

@ -849,6 +849,10 @@ MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
(video ? video->GetEndTime() : -1),
(video ? video->mDiscontinuity : 0));
// Check frame validity here for every decoded frame in order to have a
// better chance to make the decision of turning off HW acceleration.
CheckFrameValidity(aVideoSample->As<VideoData>());
switch (mState) {
case DECODER_STATE_BUFFERING: {
// If we're buffering, this may be the sample we need to stop buffering.
@ -2448,16 +2452,11 @@ MediaDecoderStateMachine::Reset()
DecodeTaskQueue()->Dispatch(resetTask.forget());
}
bool MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
void
MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
{
MOZ_ASSERT(OnTaskQueue());
// If we've sent this frame before then only return the valid state,
// don't update the statistics.
if (aData->mSentToCompositor) {
return !aData->mImage || aData->mImage->IsValid();
}
// Update corrupt-frames statistics
if (aData->mImage && !aData->mImage->IsValid()) {
FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
@ -2475,10 +2474,8 @@ bool MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
mCorruptFrames.clear();
gfxCriticalNote << "Too many dropped/corrupted frames, disabling DXVA";
}
return false;
} else {
mCorruptFrames.insert(0);
return true;
}
}
@ -2500,7 +2497,7 @@ void MediaDecoderStateMachine::RenderVideoFrames(int32_t aMaxFrames,
for (uint32_t i = 0; i < frames.Length(); ++i) {
VideoData* frame = frames[i]->As<VideoData>();
bool valid = CheckFrameValidity(frame);
bool valid = !frame->mImage || frame->mImage->IsValid();
frame->mSentToCompositor = true;
if (!valid) {

View File

@ -463,8 +463,9 @@ protected:
// machine thread, caller must hold the decoder lock.
void UpdatePlaybackPositionInternal(int64_t aTime);
// Decode monitor must be held.
bool CheckFrameValidity(VideoData* aData);
// Decode monitor must be held. To determine if MDSM needs to turn off HW
// acceleration.
void CheckFrameValidity(VideoData* aData);
// Sets VideoQueue images into the VideoFrameContainer. Called on the shared
// state machine thread. Decode monitor must be held. The first aMaxFrames

View File

@ -1,5 +1,5 @@
[DEFAULT]
skip-if = e10s || buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
support-files =
mediasource.js
seek.webm seek.webm^headers^

View File

@ -66,7 +66,7 @@ public:
return mPorts[aIndex];
}
public:
private:
nsCOMPtr<nsISupports> mOwner;
nsTArray<nsRefPtr<MessagePort>> mPorts;
};

View File

@ -44,6 +44,12 @@ interface MessageEvent : Event {
* data, origin, source, and lastEventId attributes of this appropriately.
*/
readonly attribute MessagePortList? ports;
[Throws]
void initMessageEvent(DOMString type, boolean bubbles, boolean cancelable,
any data, DOMString origin, DOMString lastEventId,
(WindowProxy or MessagePort)? source,
sequence<MessagePort>? ports);
};
dictionary MessageEventInit : EventInit {

View File

@ -6393,25 +6393,25 @@ nsHTMLEditRules::ReturnInHeader(Selection* aSelection,
nsIDOMNode *aNode,
int32_t aOffset)
{
NS_ENSURE_TRUE(aSelection && aHeader && aNode, NS_ERROR_NULL_POINTER);
nsCOMPtr<Element> header = do_QueryInterface(aHeader);
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
NS_ENSURE_TRUE(aSelection && header && node, NS_ERROR_NULL_POINTER);
// remeber where the header is
int32_t offset;
nsCOMPtr<nsIDOMNode> headerParent = nsEditor::GetNodeLocation(aHeader, &offset);
// get ws code to adjust any ws
nsCOMPtr<nsINode> selNode(do_QueryInterface(aNode));
NS_ENSURE_STATE(mHTMLEditor);
nsresult res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor,
address_of(selNode),
address_of(node),
&aOffset);
NS_ENSURE_SUCCESS(res, res);
// split the header
int32_t newOffset;
NS_ENSURE_STATE(node->IsContent());
NS_ENSURE_STATE(mHTMLEditor);
res = mHTMLEditor->SplitNodeDeep(aHeader, GetAsDOMNode(selNode), aOffset, &newOffset);
NS_ENSURE_SUCCESS(res, res);
mHTMLEditor->SplitNodeDeep(*header, *node->AsContent(), aOffset);
// if the leftand heading is empty, put a mozbr in it
nsCOMPtr<nsIDOMNode> prevItem;
@ -6598,13 +6598,14 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
nsCOMPtr<nsIDOMNode> *aSelNode,
int32_t *aOffset)
{
NS_ENSURE_TRUE(aPara && aBRNode && aSelNode && *aSelNode && aOffset && aSelection, NS_ERROR_NULL_POINTER);
nsCOMPtr<Element> para = do_QueryInterface(aPara);
NS_ENSURE_TRUE(para && aBRNode && aSelNode && *aSelNode && aOffset &&
aSelection, NS_ERROR_NULL_POINTER);
nsresult res = NS_OK;
// split para
int32_t newOffset;
// get ws code to adjust any ws
nsCOMPtr<nsIDOMNode> leftPara, rightPara;
nsCOMPtr<nsIContent> leftPara, rightPara;
NS_ENSURE_STATE(mHTMLEditor);
nsCOMPtr<nsINode> selNode(do_QueryInterface(*aSelNode));
res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), aOffset);
@ -6612,9 +6613,11 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
NS_ENSURE_SUCCESS(res, res);
// split the paragraph
NS_ENSURE_STATE(mHTMLEditor);
res = mHTMLEditor->SplitNodeDeep(aPara, *aSelNode, *aOffset, &newOffset, false,
address_of(leftPara), address_of(rightPara));
NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_STATE(selNode->IsContent());
mHTMLEditor->SplitNodeDeep(*para, *selNode->AsContent(), *aOffset,
nsHTMLEditor::EmptyContainers::yes,
getter_AddRefs(leftPara),
getter_AddRefs(rightPara));
// get rid of the break, if it is visible (otherwise it may be needed to prevent an empty p)
NS_ENSURE_STATE(mHTMLEditor);
if (mHTMLEditor->IsVisBreak(aBRNode))
@ -6631,9 +6634,9 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
NS_ENSURE_SUCCESS(res, res);
// check both halves of para to see if we need mozBR
res = InsertMozBRIfNeeded(leftPara);
res = InsertMozBRIfNeeded(GetAsDOMNode(leftPara));
NS_ENSURE_SUCCESS(res, res);
res = InsertMozBRIfNeeded(rightPara);
res = InsertMozBRIfNeeded(GetAsDOMNode(rightPara));
NS_ENSURE_SUCCESS(res, res);
// selection to beginning of right hand para;
@ -6751,10 +6754,9 @@ nsHTMLEditRules::ReturnInListItem(Selection* aSelection,
res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), &aOffset);
NS_ENSURE_SUCCESS(res, res);
// now split list item
int32_t newOffset;
NS_ENSURE_STATE(mHTMLEditor);
res = mHTMLEditor->SplitNodeDeep(aListItem, GetAsDOMNode(selNode), aOffset, &newOffset, false);
NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_STATE(selNode->IsContent());
mHTMLEditor->SplitNodeDeep(*listItem, *selNode->AsContent(), aOffset);
// hack: until I can change the damaged doc range code back to being
// extra inclusive, I have to manually detect certain list items that
// may be left empty.
@ -7156,14 +7158,15 @@ nsHTMLEditRules::SplitAsNeeded(nsIAtom& aTag,
// Could not find a place to build tag!
return NS_ERROR_FAILURE;
}
if (splitNode) {
if (splitNode && splitNode->IsContent() && inOutParent->IsContent()) {
// We found a place for block, but above inOutParent. We need to split.
NS_ENSURE_STATE(mHTMLEditor);
nsresult res = mHTMLEditor->SplitNodeDeep(splitNode->AsDOMNode(),
inOutParent->AsDOMNode(),
inOutOffset, &inOutOffset);
NS_ENSURE_SUCCESS(res, res);
int32_t offset = mHTMLEditor->SplitNodeDeep(*splitNode->AsContent(),
*inOutParent->AsContent(),
inOutOffset);
NS_ENSURE_STATE(offset != -1);
inOutParent = tagParent;
inOutOffset = offset;
}
return NS_OK;
}

View File

@ -1583,10 +1583,10 @@ nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode,
NS_ENSURE_TRUE(ioOffset, NS_ERROR_NULL_POINTER);
nsresult res = NS_OK;
nsCOMPtr<nsINode> parent = do_QueryInterface(*ioParent);
nsCOMPtr<nsIContent> parent = do_QueryInterface(*ioParent);
NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsINode> topChild = parent;
int32_t offsetOfInsert = *ioOffset;
nsCOMPtr<nsIContent> topChild = parent;
nsCOMPtr<nsIContent> origParent = parent;
// Search up the parent chain to find a suitable container
while (!CanContain(*parent, *node)) {
@ -1602,24 +1602,24 @@ nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode,
// There's no suitable place to put the node in this editing host. Maybe
// someone is trying to put block content in a span. So just put it
// where we were originally asked.
parent = topChild = do_QueryInterface(*ioParent);
NS_ENSURE_STATE(parent);
parent = topChild = origParent;
break;
}
topChild = parent;
parent = parent->GetParentNode();
parent = parent->GetParent();
}
if (parent != topChild)
{
// we need to split some levels above the original selection parent
res = SplitNodeDeep(GetAsDOMNode(topChild), *ioParent, *ioOffset,
&offsetOfInsert, aNoEmptyNodes);
NS_ENSURE_SUCCESS(res, res);
int32_t offset = SplitNodeDeep(*topChild, *origParent, *ioOffset,
aNoEmptyNodes ? EmptyContainers::no
: EmptyContainers::yes);
NS_ENSURE_STATE(offset != -1);
*ioParent = GetAsDOMNode(parent);
*ioOffset = offsetOfInsert;
*ioOffset = offset;
}
// Now we can insert the new node
res = InsertNode(*node, *parent, offsetOfInsert);
res = InsertNode(*node, *parent, *ioOffset);
return res;
}
@ -1927,30 +1927,31 @@ nsHTMLEditor::MakeOrChangeList(const nsAString& aListType, bool entireList, cons
// Find out if the selection is collapsed:
bool isCollapsed = selection->Collapsed();
nsCOMPtr<nsINode> node;
int32_t offset;
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
if (!node) res = NS_ERROR_FAILURE;
NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_TRUE(selection->GetRangeAt(0) &&
selection->GetRangeAt(0)->GetStartParent() &&
selection->GetRangeAt(0)->GetStartParent()->IsContent(),
NS_ERROR_FAILURE);
OwningNonNull<nsIContent> node =
*selection->GetRangeAt(0)->GetStartParent()->AsContent();
int32_t offset = selection->GetRangeAt(0)->StartOffset();
if (isCollapsed)
{
// have to find a place to put the list
nsCOMPtr<nsINode> parent = node;
nsCOMPtr<nsINode> topChild = node;
nsCOMPtr<nsIContent> parent = node;
nsCOMPtr<nsIContent> topChild = node;
nsCOMPtr<nsIAtom> listAtom = do_GetAtom(aListType);
while (!CanContainTag(*parent, *listAtom)) {
topChild = parent;
parent = parent->GetParentNode();
parent = parent->GetParent();
}
if (parent != node)
{
// we need to split up to the child of parent
res = SplitNodeDeep(GetAsDOMNode(topChild), GetAsDOMNode(node), offset,
&offset);
NS_ENSURE_SUCCESS(res, res);
offset = SplitNodeDeep(*topChild, *node, offset);
NS_ENSURE_STATE(offset != -1);
}
// make a list
@ -2058,31 +2059,32 @@ nsHTMLEditor::InsertBasicBlock(const nsAString& aBlockType)
// Find out if the selection is collapsed:
bool isCollapsed = selection->Collapsed();
nsCOMPtr<nsINode> node;
int32_t offset;
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
if (!node) res = NS_ERROR_FAILURE;
NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_TRUE(selection->GetRangeAt(0) &&
selection->GetRangeAt(0)->GetStartParent() &&
selection->GetRangeAt(0)->GetStartParent()->IsContent(),
NS_ERROR_FAILURE);
OwningNonNull<nsIContent> node =
*selection->GetRangeAt(0)->GetStartParent()->AsContent();
int32_t offset = selection->GetRangeAt(0)->StartOffset();
if (isCollapsed)
{
// have to find a place to put the block
nsCOMPtr<nsINode> parent = node;
nsCOMPtr<nsINode> topChild = node;
nsCOMPtr<nsIContent> parent = node;
nsCOMPtr<nsIContent> topChild = node;
nsCOMPtr<nsIAtom> blockAtom = do_GetAtom(aBlockType);
while (!CanContainTag(*parent, *blockAtom)) {
NS_ENSURE_TRUE(parent->GetParentNode(), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(parent->GetParent(), NS_ERROR_FAILURE);
topChild = parent;
parent = parent->GetParentNode();
parent = parent->GetParent();
}
if (parent != node)
{
// we need to split up to the child of parent
res = SplitNodeDeep(GetAsDOMNode(topChild), GetAsDOMNode(node), offset,
&offset);
NS_ENSURE_SUCCESS(res, res);
offset = SplitNodeDeep(*topChild, *node, offset);
NS_ENSURE_STATE(offset != -1);
}
// make a block
@ -2128,33 +2130,34 @@ nsHTMLEditor::Indent(const nsAString& aIndent)
if (!handled)
{
// Do default - insert a blockquote node if selection collapsed
nsCOMPtr<nsINode> node;
int32_t offset;
bool isCollapsed = selection->Collapsed();
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
if (!node) res = NS_ERROR_FAILURE;
NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_TRUE(selection->GetRangeAt(0) &&
selection->GetRangeAt(0)->GetStartParent() &&
selection->GetRangeAt(0)->GetStartParent()->IsContent(),
NS_ERROR_FAILURE);
OwningNonNull<nsIContent> node =
*selection->GetRangeAt(0)->GetStartParent()->AsContent();
int32_t offset = selection->GetRangeAt(0)->StartOffset();
if (aIndent.EqualsLiteral("indent"))
{
if (isCollapsed)
{
// have to find a place to put the blockquote
nsCOMPtr<nsINode> parent = node;
nsCOMPtr<nsINode> topChild = node;
nsCOMPtr<nsIContent> parent = node;
nsCOMPtr<nsIContent> topChild = node;
while (!CanContainTag(*parent, *nsGkAtoms::blockquote)) {
NS_ENSURE_TRUE(parent->GetParentNode(), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(parent->GetParent(), NS_ERROR_FAILURE);
topChild = parent;
parent = parent->GetParentNode();
parent = parent->GetParent();
}
if (parent != node)
{
// we need to split up to the child of parent
res = SplitNodeDeep(GetAsDOMNode(topChild), GetAsDOMNode(node),
offset, &offset);
NS_ENSURE_SUCCESS(res, res);
offset = SplitNodeDeep(*topChild, *node, offset);
NS_ENSURE_STATE(offset != -1);
}
// make a blockquote
@ -2166,9 +2169,9 @@ nsHTMLEditor::Indent(const nsAString& aIndent)
res = InsertText(NS_LITERAL_STRING(" "));
NS_ENSURE_SUCCESS(res, res);
// reposition selection to before the space character
res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
NS_ENSURE_SUCCESS(res, res);
res = selection->Collapse(node,0);
NS_ENSURE_STATE(selection->GetRangeAt(0));
res = selection->Collapse(selection->GetRangeAt(0)->GetStartParent(),
0);
NS_ENSURE_SUCCESS(res, res);
}
}

View File

@ -592,12 +592,22 @@ nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsIDOMNode> *aNode,
// or the style is specified in the style attribute
isSet) {
// found a style node we need to split
nsresult rv = SplitNodeDeep(GetAsDOMNode(node), *aNode, *aOffset,
&offset, false, outLeftNode, outRightNode);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIContent> outLeftContent, outRightContent;
nsCOMPtr<nsIContent> nodeParam = do_QueryInterface(*aNode);
NS_ENSURE_STATE(nodeParam || !*aNode);
offset = SplitNodeDeep(*node, *nodeParam, *aOffset, EmptyContainers::yes,
getter_AddRefs(outLeftContent),
getter_AddRefs(outRightContent));
NS_ENSURE_TRUE(offset != -1, NS_ERROR_FAILURE);
// reset startNode/startOffset
*aNode = GetAsDOMNode(node->GetParent());
*aOffset = offset;
if (outLeftNode) {
*outLeftNode = GetAsDOMNode(outLeftContent);
}
if (outRightNode) {
*outRightNode = GetAsDOMNode(outRightContent);
}
}
node = node->GetParent();
}

View File

@ -837,20 +837,18 @@ DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat)
aSize.width, aSize.height,
GfxFormatToSkiaColorType(aFormat),
alphaType);
// we need to have surfaces that have a stride aligned to 4 for interop with cairo
int stride = (BytesPerPixel(aFormat)*aSize.width + (4-1)) & -4;
SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(skiInfo));
if (!device) {
return false;
}
SkBitmap bitmap = device->accessBitmap(true);
SkBitmap bitmap;
bitmap.setInfo(skiInfo, stride);
if (!bitmap.allocPixels()) {
return false;
}
bitmap.eraseARGB(0, 0, 0, 0);
mCanvas.adopt(new SkCanvas(device.get()));
mCanvas.adopt(new SkCanvas(bitmap));
mSize = aSize;
mFormat = aFormat;

View File

@ -64,6 +64,11 @@ SourceSurfaceD2DTarget::GetDataSurface()
desc.BindFlags = 0;
desc.MiscFlags = 0;
if (!Factory::GetDirect3D10Device()) {
gfxCriticalError() << "Invalid D3D10 device in D2D target surface";
return nullptr;
}
HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(dataSurf->mTexture));
if (FAILED(hr)) {

View File

@ -1352,6 +1352,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
SymLoadStruct mapBufferRangeSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fMapBufferRange, { "MapBufferRange", nullptr } },
{ (PRFuncPtr*) &mSymbols.fFlushMappedBufferRange, { "FlushMappedBufferRange", nullptr } },
{ (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } },
END_SYMBOLS
};

View File

@ -734,6 +734,16 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
}
}
static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
SkASSERT(matrix.rectStaysRect());
SkASSERT(SkPaint::kFill_Style != paint.getStyle());
SkVector size;
SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
matrix.mapVectors(&size, &pt, 1);
return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
}
static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
SkPoint* strokeSize) {
if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
@ -812,12 +822,22 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
devRect.sort();
// look for the quick exit, before we build a blitter
SkIRect ir;
devRect.roundOut(&ir);
SkRect bbox = devRect;
if (paint.getStyle() != SkPaint::kFill_Style) {
// extra space for hairlines
ir.inset(-1, -1);
if (paint.getStrokeWidth() == 0) {
bbox.outset(1, 1);
} else {
// For kStroke_RectType, strokeSize is already computed.
const SkPoint& ssize = (kStroke_RectType == rtype)
? strokeSize
: compute_stroke_size(paint, *fMatrix);
bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
}
}
SkIRect ir;
bbox.roundOut(&ir);
if (fRC->quickReject(ir)) {
return;
}

View File

@ -2157,13 +2157,9 @@ gfxPlatform::PerfWarnings()
return gfxPrefs::PerfWarnings();
}
void
gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends)
static inline bool
AllowOpenGL(bool* aWhitelisted)
{
// Being whitelisted is not enough to accelerate, but not being whitelisted is
// enough not to:
bool whitelisted = false;
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
if (gfxInfo) {
// bug 655578: on X11 at least, we must always call GetData (even if we don't need that information)
@ -2175,12 +2171,26 @@ gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends
int32_t status;
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status))) {
if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
whitelisted = true;
*aWhitelisted = true;
return true;
}
}
}
return gfxPrefs::LayersAccelerationForceEnabled();
}
void
gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends)
{
// Being whitelisted is not enough to accelerate, but not being whitelisted is
// enough not to:
bool whitelisted = false;
if (AllowOpenGL(&whitelisted)) {
aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
}
if (!whitelisted) {
static int tell_me_once = 0;
if (!tell_me_once) {

View File

@ -1967,6 +1967,10 @@ gfxWindowsPlatform::CheckD3D11Support(bool* aCanUseHardware)
*aCanUseHardware = false;
return FeatureStatus::Available;
}
if (gfxPrefs::LayersAccelerationForceEnabled()) {
*aCanUseHardware = true;
return FeatureStatus::Available;
}
if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) {
int32_t status;

View File

@ -1792,6 +1792,7 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
#elif defined(JS_CODEGEN_ARM64)
MOZ_CRASH();
void* callee = nullptr;
(void)callerRetAddr;
#elif defined(JS_CODEGEN_MIPS32)
Instruction* instr = (Instruction*)(callerRetAddr - 4 * sizeof(uint32_t));
void* callee = (void*)Assembler::ExtractLuiOriValue(instr, instr->next());
@ -1817,6 +1818,7 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
#elif defined(JS_CODEGEN_ARM)
new (caller) InstBLImm(BOffImm(newCallee - caller), Assembler::Always);
#elif defined(JS_CODEGEN_ARM64)
(void)newCallee;
MOZ_CRASH();
#elif defined(JS_CODEGEN_MIPS32)
Assembler::WriteLuiOriInstructions(instr, instr->next(),
@ -1882,6 +1884,8 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
new (jump) InstNOP();
}
#elif defined(JS_CODEGEN_ARM64)
(void)jump;
(void)profilingEpilogue;
MOZ_CRASH();
#elif defined(JS_CODEGEN_MIPS32)
Instruction* instr = (Instruction*)jump;

View File

@ -3111,13 +3111,20 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_NEW:
case PNK_TAGGED_TEMPLATE:
case PNK_CALL:
case PNK_SUPERCALL:
{
ParseNode* next = pn->pn_head;
MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
RootedValue callee(cx);
if (!expression(next, &callee))
return false;
if (pn->isKind(PNK_SUPERCALL)) {
MOZ_ASSERT(next->isKind(PNK_POSHOLDER));
if (!builder.super(&next->pn_pos, &callee))
return false;
} else {
if (!expression(next, &callee))
return false;
}
NodeVector args(cx);
if (!args.reserve(pn->pn_count - 1))
@ -3135,6 +3142,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
if (pn->getKind() == PNK_TAGGED_TEMPLATE)
return builder.taggedTemplate(callee, args, &pn->pn_pos, dst);
// SUPERCALL is Call(super, args)
return pn->isKind(PNK_NEW)
? builder.newExpression(callee, args, &pn->pn_pos, dst)

View File

@ -868,7 +868,7 @@ SetSavedStacksRNGState(JSContext* cx, unsigned argc, Value* vp)
if (!ToInt32(cx, args[0], &seed))
return false;
cx->compartment()->savedStacks().setRNGState((seed ^ RNG_MULTIPLIER) & RNG_MASK);
cx->compartment()->savedStacks().setRNGState(seed, seed * 33);
return true;
}

View File

@ -1934,7 +1934,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
case PNK_THIS:
case PNK_ELISION:
case PNK_GENERATOR:
case PNK_NUMBER:
@ -1943,6 +1942,12 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = false;
return true;
// |this| can throw in derived class constructors.
case PNK_THIS:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
*answer = sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor();
return true;
// Trivial binary nodes with more token pos holders.
case PNK_NEWTARGET:
MOZ_ASSERT(pn->isArity(PN_BINARY));
@ -2185,6 +2190,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_NEW:
case PNK_CALL:
case PNK_TAGGED_TEMPLATE:
case PNK_SUPERCALL:
MOZ_ASSERT(pn->isArity(PN_LIST));
*answer = true;
return true;
@ -6727,6 +6733,12 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
}
callop = false;
break;
case PNK_POSHOLDER:
MOZ_ASSERT(pn->isKind(PNK_SUPERCALL));
MOZ_ASSERT(parser->handler.isSuperBase(pn2, cx));
if (!emit1(JSOP_SUPERFUN))
return false;
break;
default:
if (!emitTree(pn2))
return false;
@ -6739,7 +6751,8 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
return false;
}
bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW;
bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW ||
pn->getOp() == JSOP_SUPERCALL || pn->getOp() == JSOP_SPREADSUPERCALL;;
/*
* Emit code for each argument in order, then emit the JSOP_*CALL or
@ -6755,17 +6768,27 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
}
if (isNewOp) {
// Repush the callee as new.target
if (!emitDupAt(argc + 1))
return false;
if (pn->isKind(PNK_SUPERCALL)) {
if (!emit1(JSOP_NEWTARGET))
return false;
} else {
// Repush the callee as new.target
if (!emitDupAt(argc + 1))
return false;
}
}
} else {
if (!emitArray(pn2->pn_next, argc, JSOP_SPREADCALLARRAY))
return false;
if (isNewOp) {
if (!emitDupAt(2))
return false;
if (pn->isKind(PNK_SUPERCALL)) {
if (!emit1(JSOP_NEWTARGET))
return false;
} else {
if (!emitDupAt(2))
return false;
}
}
}
emittingForInit = oldEmittingForInit;
@ -6791,6 +6814,9 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS))
return false;
}
if (pn->isKind(PNK_SUPERCALL) && !emit1(JSOP_SETTHIS))
return false;
return true;
}
@ -7847,6 +7873,7 @@ BytecodeEmitter::emitTree(ParseNode* pn)
case PNK_TAGGED_TEMPLATE:
case PNK_CALL:
case PNK_GENEXP:
case PNK_SUPERCALL:
ok = emitCallOrNew(pn);
break;

View File

@ -414,6 +414,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_CLASSNAMES:
case PNK_NEWTARGET:
case PNK_POSHOLDER:
case PNK_SUPERCALL:
MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on "
"some parent node without recurring to test this node");
@ -1579,7 +1580,8 @@ static bool
FoldCall(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
bool inGenexpLambda)
{
MOZ_ASSERT(node->isKind(PNK_CALL) || node->isKind(PNK_TAGGED_TEMPLATE));
MOZ_ASSERT(node->isKind(PNK_CALL) || node->isKind(PNK_SUPERCALL) ||
node->isKind(PNK_TAGGED_TEMPLATE));
MOZ_ASSERT(node->isArity(PN_LIST));
// Don't fold a parenthesized callable component in an invocation, as this
@ -1876,6 +1878,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
return FoldAdd(cx, pnp, parser, inGenexpLambda);
case PNK_CALL:
case PNK_SUPERCALL:
case PNK_TAGGED_TEMPLATE:
return FoldCall(cx, pn, parser, inGenexpLambda);

View File

@ -376,6 +376,7 @@ class NameResolver
case PNK_EXPORT_BATCH_SPEC:
case PNK_FRESHENBLOCK:
case PNK_OBJECT_PROPERTY_NAME:
case PNK_POSHOLDER:
MOZ_ASSERT(cur->isArity(PN_NULLARY));
break;
@ -673,6 +674,7 @@ class NameResolver
case PNK_COMMA:
case PNK_NEW:
case PNK_CALL:
case PNK_SUPERCALL:
case PNK_GENEXP:
case PNK_ARRAY:
case PNK_STATEMENTLIST:
@ -796,7 +798,6 @@ class NameResolver
case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST
case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
case PNK_CLASSNAMES: // by PNK_CLASS
case PNK_POSHOLDER: // by PNK_NEWTARGET, PNK_DOT
MOZ_CRASH("should have been handled by a parent node");
case PNK_LIMIT: // invalid sentinel value

View File

@ -489,6 +489,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_COMMA:
case PNK_NEW:
case PNK_CALL:
case PNK_SUPERCALL:
case PNK_GENEXP:
case PNK_ARRAY:
case PNK_OBJECT:

View File

@ -175,6 +175,7 @@ class PackedScopeCoordinate
F(CLASSNAMES) \
F(NEWTARGET) \
F(POSHOLDER) \
F(SUPERCALL) \
\
/* Unary operators. */ \
F(TYPEOFNAME) \

View File

@ -8648,9 +8648,31 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
tt == TOK_NO_SUBS_TEMPLATE)
{
if (handler.isSuperBase(lhs, context)) {
// For now...
report(ParseError, false, null(), JSMSG_BAD_SUPER);
return null();
if (!pc->sc->isFunctionBox() || !pc->sc->asFunctionBox()->isDerivedClassConstructor()) {
report(ParseError, false, null(), JSMSG_BAD_SUPERCALL);
return null();
}
if (tt != TOK_LP) {
report(ParseError, false, null(), JSMSG_BAD_SUPER);
return null();
}
nextMember = handler.newList(PNK_SUPERCALL, lhs, JSOP_SUPERCALL);
if (!nextMember)
return null();
// Despite the fact that it's impossible to have |super()| is a
// generator, we still inherity the yieldHandling of the
// memberExpression, per spec. Curious.
bool isSpread = false;
if (!argumentList(yieldHandling, nextMember, &isSpread))
return null();
if (isSpread)
handler.setOp(nextMember, JSOP_SPREADSUPERCALL);
return nextMember;
}
nextMember = tt == TOK_LP ? handler.newCall() : handler.newTaggedTemplate();

View File

@ -374,6 +374,7 @@ class FunctionBox : public ObjectBox, public SharedContext
hasExtensibleScope() ||
needsDeclEnvObject() ||
needsHomeObject() ||
isDerivedClassConstructor() ||
isGenerator();
}
};

View File

@ -1,4 +1,4 @@
// |jit-test| error:InternalError
// |jit-test| error:TypeError
// Binary: cache/js-dbg-32-4ce3983a43f4-linux
// Flags:

View File

@ -1,13 +1,15 @@
// |jit-test| error: ExitCleanly
assertEq((new (Proxy.createFunction({},
var handler = { getPropertyDescriptor() { return undefined; } }
assertEq((new (Proxy.createFunction(handler,
function(){ this.x = 1 },
function(){ this.x = 2 }))).x, 2);
// proxies can return the callee
var x = Proxy.createFunction({}, function (q) { return q; });
var x = Proxy.createFunction(handler, function (q) { return q; });
assertEq(new x(x), x);
try {
var x = (Proxy.createFunction({}, "".indexOf));
var x = (Proxy.createFunction(handler, "".indexOf));
new x;
throw "Should not be reached"
}

View File

@ -32,5 +32,5 @@ dbg.memory.trackingAllocationSites = true;
// probability is fine.
measure(0.0, 0);
measure(1.0, 100);
measure(0.1, 9);
measure(0.5, 51);
measure(0.1, 7);
measure(0.5, 44);

View File

@ -6,18 +6,3 @@ evalcx("\
f();\
f();\
", newGlobal());
// Test 2: Don't take the prototype of proxy's to create |this|,
// as this will throw... Not expected behaviour.
var O = new Proxy(function() {}, {
get: function() {
throw "get trap";
}
});
function f() {
new O();
}
f();
f();

View File

@ -980,7 +980,7 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
#endif
bool pushedNewTarget = op == JSOP_NEW;
// If this was the last inline frame, or we are bailing out to a catch or
// finally block in this frame, then unpacking is almost done.
if (!iter.moreFrames() || catchingException) {
@ -1877,6 +1877,8 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
case Bailout_NonSimdFloat32x4Input:
case Bailout_InitialState:
case Bailout_Debugger:
case Bailout_UninitializedThis:
case Bailout_BadDerivedConstructorReturn:
// Do nothing.
break;

View File

@ -1285,6 +1285,30 @@ BaselineCompiler::emit_JSOP_NULL()
return true;
}
typedef bool (*ThrowUninitializedThisFn)(JSContext*, BaselineFrame* frame);
static const VMFunction ThrowUninitializedThisInfo =
FunctionInfo<ThrowUninitializedThisFn>(BaselineThrowUninitializedThis);
bool
BaselineCompiler::emitCheckThis()
{
frame.assertSyncedStack();
Label thisOK;
masm.branchTestMagic(Assembler::NotEqual, frame.addressOfThis(), &thisOK);
prepareVMCall();
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
if (!callVM(ThrowUninitializedThisInfo))
return false;
masm.bind(&thisOK);
return true;
}
bool
BaselineCompiler::emit_JSOP_THIS()
{
@ -1299,6 +1323,12 @@ BaselineCompiler::emit_JSOP_THIS()
return true;
}
if (script->isDerivedClassConstructor()) {
frame.syncStack(0);
if (!emitCheckThis())
return false;
}
// Keep this value in R0
frame.pushThis();
@ -2873,7 +2903,7 @@ BaselineCompiler::emitCall()
{
MOZ_ASSERT(IsCallPC(pc));
bool construct = JSOp(*pc) == JSOP_NEW;
bool construct = JSOp(*pc) == JSOP_NEW || JSOp(*pc) == JSOP_SUPERCALL;
uint32_t argc = GET_ARGC(pc);
frame.syncStack(0);
@ -2900,13 +2930,13 @@ BaselineCompiler::emitSpreadCall()
masm.move32(Imm32(1), R0.scratchReg());
// Call IC
ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ JSOp(*pc) == JSOP_SPREADNEW,
bool construct = JSOp(*pc) == JSOP_SPREADNEW || JSOp(*pc) == JSOP_SPREADSUPERCALL;
ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ construct,
/* isSpread = */ true);
if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
return false;
// Update FrameInfo.
bool construct = JSOp(*pc) == JSOP_SPREADNEW;
frame.popn(3 + construct);
frame.push(R0);
return true;
@ -2924,6 +2954,12 @@ BaselineCompiler::emit_JSOP_NEW()
return emitCall();
}
bool
BaselineCompiler::emit_JSOP_SUPERCALL()
{
return emitCall();
}
bool
BaselineCompiler::emit_JSOP_FUNCALL()
{
@ -2960,6 +2996,12 @@ BaselineCompiler::emit_JSOP_SPREADNEW()
return emitSpreadCall();
}
bool
BaselineCompiler::emit_JSOP_SPREADSUPERCALL()
{
return emitSpreadCall();
}
bool
BaselineCompiler::emit_JSOP_SPREADEVAL()
{
@ -3290,6 +3332,10 @@ BaselineCompiler::emit_JSOP_DEBUGGER()
return true;
}
typedef bool (*ThrowBadDerivedReturnFn)(JSContext*, HandleValue);
static const VMFunction ThrowBadDerivedReturnInfo =
FunctionInfo<ThrowBadDerivedReturnFn>(jit::ThrowBadDerivedReturn);
typedef bool (*DebugEpilogueFn)(JSContext*, BaselineFrame*, jsbytecode*);
static const VMFunction DebugEpilogueInfo =
FunctionInfo<DebugEpilogueFn>(jit::DebugEpilogueOnBaselineReturn);
@ -3297,6 +3343,29 @@ static const VMFunction DebugEpilogueInfo =
bool
BaselineCompiler::emitReturn()
{
if (script->isDerivedClassConstructor()) {
frame.syncStack(0);
Label derivedDone, returnOK;
masm.branchTestObject(Assembler::Equal, JSReturnOperand, &derivedDone);
masm.branchTestUndefined(Assembler::Equal, JSReturnOperand, &returnOK);
// This is going to smash JSReturnOperand, but we don't care, because it's
// also going to throw unconditionally.
prepareVMCall();
pushArg(JSReturnOperand);
if (!callVM(ThrowBadDerivedReturnInfo))
return false;
masm.assumeUnreachable("Should throw on bad derived constructor return");
masm.bind(&returnOK);
if (!emitCheckThis())
return false;
masm.bind(&derivedDone);
}
if (compileDebugInstrumentation_) {
// Move return value into the frame's rval slot.
masm.storeValue(JSReturnOperand, frame.addressOfReturnValue());

View File

@ -201,7 +201,9 @@ namespace jit {
_(JSOP_SETRVAL) \
_(JSOP_RETRVAL) \
_(JSOP_RETURN) \
_(JSOP_NEWTARGET)
_(JSOP_NEWTARGET) \
_(JSOP_SUPERCALL) \
_(JSOP_SPREADSUPERCALL)
class BaselineCompiler : public BaselineCompilerSpecific
{
@ -305,6 +307,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
bool emitFormalArgAccess(uint32_t arg, bool get);
bool emitUninitializedLexicalCheck(const ValueOperand& val);
bool emitCheckThis();
bool addPCMappingEntry(bool addIndexEntry);

View File

@ -395,6 +395,8 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, JSScript* script,
}
if (val.isPrimitive()) {
if (val.isMagic(JS_UNINITIALIZED_LEXICAL))
return true;
MOZ_ASSERT(!val.isMagic());
JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
@ -503,10 +505,15 @@ DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallbac
{
// It's possible that we arrived here from bailing out of Ion, and that
// Ion proved that the value is dead and optimized out. In such cases, do
// nothing.
if (value.isMagic(JS_OPTIMIZED_OUT)) {
res.set(value);
return true;
// nothing. However, it's also possible that we have an uninitialized this,
// in which case we should not look for other magic values.
if (stub->monitorsThis()) {
MOZ_ASSERT_IF(value.isMagic(), value.isMagic(JS_UNINITIALIZED_LEXICAL));
} else {
if (value.isMagic(JS_OPTIMIZED_OUT)) {
res.set(value);
return true;
}
}
RootedScript script(cx, frame->script());
@ -516,7 +523,10 @@ DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, ICTypeMonitor_Fallbac
uint32_t argument;
if (stub->monitorsThis()) {
MOZ_ASSERT(pc == script->code());
TypeScript::SetThis(cx, script, value);
if (value.isMagic(JS_UNINITIALIZED_LEXICAL))
TypeScript::SetThis(cx, script, TypeSet::UnknownType());
else
TypeScript::SetThis(cx, script, value);
} else if (stub->monitorsArgument(&argument)) {
MOZ_ASSERT(pc == script->code());
TypeScript::SetArgument(cx, script, argument, value);
@ -5015,6 +5025,18 @@ TryAttachGlobalNameAccessorStub(JSContext* cx, HandleScript script, jsbytecode*
ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
// The CallNativeGlobal stub needs to generate 3 shape checks:
//
// 1. The global lexical scope shape check.
// 2. The global object shape check.
// 3. The holder shape check.
//
// 1 is done as the receiver check, as for GETNAME the global lexical scope is in the
// receiver position. 2 is done as a manual check that other GetProp stubs don't do. 3 is
// done as the holder check per normal.
//
// In the case the holder is the global object, check 2 is redundant but is not yet
// optimized away.
JitSpew(JitSpew_BaselineIC, " Generating GetName(GlobalName/NativeGetter) stub");
if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallNativeGlobal, current,
globalLexical, getter))
@ -8622,6 +8644,8 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
JSOp op, uint32_t argc, Value* vp, bool constructing, bool isSpread,
bool createSingleton, bool* handled)
{
bool isSuper = op == JSOP_SUPERCALL || op == JSOP_SPREADSUPERCALL;
if (createSingleton || op == JSOP_EVAL || op == JSOP_STRICTEVAL)
return true;
@ -8729,9 +8753,11 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
// Remember the template object associated with any script being called
// as a constructor, for later use during Ion compilation.
// as a constructor, for later use during Ion compilation. This is unsound
// for super(), as a single callsite can have multiple possible prototype object
// created (via different newTargets)
RootedObject templateObject(cx);
if (constructing) {
if (constructing && !isSuper) {
// If we are calling a constructor for which the new script
// properties analysis has not been performed yet, don't attach a
// stub. After the analysis is performed, CreateThisForFunction may
@ -8740,15 +8766,16 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
// Only attach a stub if the function already has a prototype and
// we can look it up without causing side effects.
RootedObject newTarget(cx, &vp[2 + argc].toObject());
RootedValue protov(cx);
if (!GetPropertyPure(cx, fun, NameToId(cx->names().prototype), protov.address())) {
if (!GetPropertyPure(cx, newTarget, NameToId(cx->names().prototype), protov.address())) {
JitSpew(JitSpew_BaselineIC, " Can't purely lookup function prototype");
return true;
}
if (protov.isObject()) {
TaggedProto proto(&protov.toObject());
ObjectGroup* group = ObjectGroup::defaultNewGroup(cx, nullptr, proto, fun);
ObjectGroup* group = ObjectGroup::defaultNewGroup(cx, nullptr, proto, newTarget);
if (!group)
return false;
@ -8762,7 +8789,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
}
}
JSObject* thisObject = CreateThisForFunction(cx, fun, TenuredObject);
JSObject* thisObject = CreateThisForFunction(cx, fun, newTarget, TenuredObject);
if (!thisObject)
return false;
@ -8830,7 +8857,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
}
RootedObject templateObject(cx);
if (MOZ_LIKELY(!isSpread)) {
if (MOZ_LIKELY(!isSpread && !isSuper)) {
bool skipAttach = false;
CallArgs args = CallArgsFromVp(argc, vp);
if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject, &skipAttach))
@ -9516,7 +9543,8 @@ ICCall_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle<Jit
isConstructing_);
}
typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, MutableHandleValue rval);
typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, HandleObject newTarget,
MutableHandleValue rval);
static const VMFunction CreateThisInfoBaseline = FunctionInfo<CreateThisFn>(CreateThis);
bool
@ -9610,24 +9638,31 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
// Stack now looks like:
// [..., Callee, ThisV, Arg0V, ..., ArgNV, NewTarget, StubFrameHeader, ArgC ]
masm.loadValue(Address(masm.getStackPointer(), STUB_FRAME_SIZE + sizeof(size_t)), R1);
masm.push(masm.extractObject(R1, ExtractTemp0));
if (isSpread_) {
masm.loadValue(Address(masm.getStackPointer(),
3 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t)), R1);
3 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t) +
sizeof(JSObject*)),
R1);
} else {
BaseValueIndex calleeSlot2(masm.getStackPointer(), argcReg,
2 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t));
2 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t) +
sizeof(JSObject*));
masm.loadValue(calleeSlot2, R1);
}
masm.push(masm.extractObject(R1, ExtractTemp0));
if (!callVM(CreateThisInfoBaseline, masm))
return false;
// Return of CreateThis must be an object.
// Return of CreateThis must be an object or uninitialized.
#ifdef DEBUG
Label createdThisIsObject;
masm.branchTestObject(Assembler::Equal, JSReturnOperand, &createdThisIsObject);
masm.assumeUnreachable("The return of CreateThis must be an object.");
masm.bind(&createdThisIsObject);
Label createdThisOK;
masm.branchTestObject(Assembler::Equal, JSReturnOperand, &createdThisOK);
masm.branchTestMagic(Assembler::Equal, JSReturnOperand, &createdThisOK);
masm.assumeUnreachable("The return of CreateThis must be an object or uninitialized.");
masm.bind(&createdThisOK);
#endif
// Reset the register set from here on in.

View File

@ -111,7 +111,8 @@ EnterBaseline(JSContext* cx, EnterJitData& data)
EnterJitCode enter = cx->runtime()->jitRuntime()->enterBaseline();
// Caller must construct |this| before invoking the Ion function.
MOZ_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
MOZ_ASSERT_IF(data.constructing, data.maxArgv[0].isObject() ||
data.maxArgv[0].isMagic(JS_UNINITIALIZED_LEXICAL));
data.result.setInt32(data.numActualArgs);
{
@ -131,9 +132,12 @@ EnterBaseline(JSContext* cx, EnterJitData& data)
MOZ_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride());
// Jit callers wrap primitive constructor return.
if (!data.result.isMagic() && data.constructing && data.result.isPrimitive())
// Jit callers wrap primitive constructor return, except for derived
// class constructors, which are forced to do it themselves.
if (!data.result.isMagic() && data.constructing && data.result.isPrimitive()) {
MOZ_ASSERT(data.maxArgv[0].isObject());
data.result = data.maxArgv[0];
}
// Release temporary buffer used for OSR into Ion.
cx->runtime()->getJitRuntime(cx)->freeOsrTempData();
@ -211,7 +215,7 @@ jit::EnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc)
return JitExec_Aborted;
vals.infallibleAppend(thisv);
if (fp->isFunctionFrame())
vals.infallibleAppend(fp->newTarget());
else
@ -306,15 +310,6 @@ CanEnterBaselineJIT(JSContext* cx, HandleScript script, InterpreterFrame* osrFra
MethodStatus
jit::CanEnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp, bool newType)
{
// If constructing, allocate a new |this| object.
if (fp->isConstructing() && fp->functionThis().isPrimitive()) {
RootedObject callee(cx, &fp->callee());
RootedObject obj(cx, CreateThisForFunction(cx, callee, newType ? SingletonObject : GenericObject));
if (!obj)
return Method_Skipped;
fp->functionThis().setObject(*obj);
}
if (!CheckFrame(fp))
return Method_CantCompile;
@ -356,8 +351,13 @@ jit::CanEnterBaselineMethod(JSContext* cx, RunState& state)
return Method_CantCompile;
}
if (!state.maybeCreateThisForConstructor(cx))
return Method_Skipped;
if (!state.maybeCreateThisForConstructor(cx)) {
if (cx->isThrowingOutOfMemory()) {
cx->recoverFromOutOfMemory();
return Method_Skipped;
}
return Method_Error;
}
} else {
MOZ_ASSERT(state.isExecute());
ExecuteType type = state.asExecute()->type();

View File

@ -4928,13 +4928,19 @@ CodeGenerator::visitInitPropGetterSetter(LInitPropGetterSetter* lir)
callVM(InitPropGetterSetterInfo, lir);
}
typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, MutableHandleValue rval);
typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval);
static const VMFunction CreateThisInfoCodeGen = FunctionInfo<CreateThisFn>(CreateThis);
void
CodeGenerator::visitCreateThis(LCreateThis* lir)
{
const LAllocation* callee = lir->getCallee();
const LAllocation* newTarget = lir->getNewTarget();
if (newTarget->isConstant())
pushArg(ImmGCPtr(&newTarget->toConstant()->toObject()));
else
pushArg(ToRegister(newTarget));
if (callee->isConstant())
pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
@ -4945,12 +4951,14 @@ CodeGenerator::visitCreateThis(LCreateThis* lir)
}
static JSObject*
CreateThisForFunctionWithProtoWrapper(JSContext* cx, js::HandleObject callee, HandleObject proto)
CreateThisForFunctionWithProtoWrapper(JSContext* cx, HandleObject callee, HandleObject newTarget,
HandleObject proto)
{
return CreateThisForFunctionWithProto(cx, callee, proto);
return CreateThisForFunctionWithProto(cx, callee, newTarget, proto);
}
typedef JSObject* (*CreateThisWithProtoFn)(JSContext* cx, HandleObject callee, HandleObject proto);
typedef JSObject* (*CreateThisWithProtoFn)(JSContext* cx, HandleObject callee,
HandleObject newTarget, HandleObject proto);
static const VMFunction CreateThisWithProtoInfo =
FunctionInfo<CreateThisWithProtoFn>(CreateThisForFunctionWithProtoWrapper);
@ -4958,6 +4966,7 @@ void
CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir)
{
const LAllocation* callee = lir->getCallee();
const LAllocation* newTarget = lir->getNewTarget();
const LAllocation* proto = lir->getPrototype();
if (proto->isConstant())
@ -4965,6 +4974,11 @@ CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir)
else
pushArg(ToRegister(proto));
if (newTarget->isConstant())
pushArg(ImmGCPtr(&newTarget->toConstant()->toObject()));
else
pushArg(ToRegister(newTarget));
if (callee->isConstant())
pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
else
@ -10325,6 +10339,19 @@ CodeGenerator::visitNewTarget(LNewTarget *ins)
masm.bind(&done);
}
void
CodeGenerator::visitCheckReturn(LCheckReturn* ins)
{
ValueOperand returnValue = ToValue(ins, LCheckReturn::ReturnValue);
ValueOperand thisValue = ToValue(ins, LCheckReturn::ThisValue);
Label bail, noChecks;
masm.branchTestObject(Assembler::Equal, returnValue, &noChecks);
masm.branchTestUndefined(Assembler::NotEqual, returnValue, &bail);
masm.branchTestMagicValue(Assembler::Equal, thisValue, JS_UNINITIALIZED_LEXICAL, &bail);
bailoutFrom(&bail, ins->snapshot());
masm.bind(&noChecks);
}
// Out-of-line math_random_no_outparam call for LRandom.
class OutOfLineRandom : public OutOfLineCodeBase<CodeGenerator>
{

View File

@ -335,6 +335,7 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitDebugger(LDebugger* ins);
void visitNewTarget(LNewTarget* ins);
void visitArrowNewTarget(LArrowNewTarget* ins);
void visitCheckReturn(LCheckReturn* ins);
void visitCheckOverRecursed(LCheckOverRecursed* lir);
void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);

View File

@ -2547,8 +2547,11 @@ jit::CanEnter(JSContext* cx, RunState& state)
}
if (!state.maybeCreateThisForConstructor(cx)) {
cx->recoverFromOutOfMemory();
return Method_Skipped;
if (cx->isThrowingOutOfMemory()) {
cx->recoverFromOutOfMemory();
return Method_Skipped;
}
return Method_Error;
}
}
@ -2659,7 +2662,8 @@ EnterIon(JSContext* cx, EnterJitData& data)
EnterJitCode enter = cx->runtime()->jitRuntime()->enterIon();
// Caller must construct |this| before invoking the Ion function.
MOZ_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
MOZ_ASSERT_IF(data.constructing,
data.maxArgv[0].isObject() || data.maxArgv[0].isMagic(JS_UNINITIALIZED_LEXICAL));
data.result.setInt32(data.numActualArgs);
{
@ -2672,9 +2676,13 @@ EnterIon(JSContext* cx, EnterJitData& data)
MOZ_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride());
// Jit callers wrap primitive constructor return.
if (!data.result.isMagic() && data.constructing && data.result.isPrimitive())
// Jit callers wrap primitive constructor return, except for derived class constructors.
if (!data.result.isMagic() && data.constructing &&
data.result.isPrimitive())
{
MOZ_ASSERT(data.maxArgv[0].isObject());
data.result = data.maxArgv[0];
}
// Release temporary buffer used for OSR into Ion.
cx->runtime()->getJitRuntime(cx)->freeOsrTempData();

View File

@ -1867,7 +1867,8 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_CALL:
case JSOP_NEW:
return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW);
case JSOP_SUPERCALL:
return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL);
case JSOP_EVAL:
case JSOP_STRICTEVAL:
@ -4469,6 +4470,15 @@ IonBuilder::processReturn(JSOp op)
MOZ_CRASH("unknown return op");
}
if (script()->isDerivedClassConstructor() &&
def->type() != MIRType_Object)
{
MOZ_ASSERT(info().funMaybeLazy() && info().funMaybeLazy()->isClassConstructor());
MCheckReturn* checkRet = MCheckReturn::New(alloc(), def, current->getSlot(info().thisSlot()));
current->add(checkRet);
def = checkRet;
}
MReturn* ret = MReturn::New(alloc(), def);
current->end(ret);
@ -4944,7 +4954,7 @@ IonBuilder::inlineScriptedCall(CallInfo& callInfo, JSFunction* target)
// Create new |this| on the caller-side for inlined constructors.
if (callInfo.constructing()) {
MDefinition* thisDefn = createThis(target, callInfo.fun());
MDefinition* thisDefn = createThis(target, callInfo.fun(), callInfo.getNewTarget());
if (!thisDefn)
return false;
callInfo.setThis(thisDefn);
@ -6038,7 +6048,7 @@ IonBuilder::createCallObject(MDefinition* callee, MDefinition* scope)
}
MDefinition*
IonBuilder::createThisScripted(MDefinition* callee)
IonBuilder::createThisScripted(MDefinition* callee, MDefinition* newTarget)
{
// Get callee.prototype.
//
@ -6053,12 +6063,12 @@ IonBuilder::createThisScripted(MDefinition* callee)
// and thus invalidation.
MInstruction* getProto;
if (!invalidatedIdempotentCache()) {
MGetPropertyCache* getPropCache = MGetPropertyCache::New(alloc(), callee, names().prototype,
MGetPropertyCache* getPropCache = MGetPropertyCache::New(alloc(), newTarget, names().prototype,
/* monitored = */ false);
getPropCache->setIdempotent();
getProto = getPropCache;
} else {
MCallGetProperty* callGetProp = MCallGetProperty::New(alloc(), callee, names().prototype,
MCallGetProperty* callGetProp = MCallGetProperty::New(alloc(), newTarget, names().prototype,
/* callprop = */ false);
callGetProp->setIdempotent();
getProto = callGetProp;
@ -6066,7 +6076,7 @@ IonBuilder::createThisScripted(MDefinition* callee)
current->add(getProto);
// Create this from prototype
MCreateThisWithProto* createThis = MCreateThisWithProto::New(alloc(), callee, getProto);
MCreateThisWithProto* createThis = MCreateThisWithProto::New(alloc(), callee, newTarget, getProto);
current->add(createThis);
return createThis;
@ -6131,6 +6141,8 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
return nullptr;
JSObject* templateObject = inspector->getTemplateObject(pc);
if (!templateObject)
return nullptr;
if (!templateObject->is<PlainObject>() && !templateObject->is<UnboxedPlainObject>())
return nullptr;
@ -6181,14 +6193,14 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
}
MDefinition*
IonBuilder::createThis(JSFunction* target, MDefinition* callee)
IonBuilder::createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget)
{
// Create |this| for unknown target.
if (!target) {
if (MDefinition* createThis = createThisScriptedBaseline(callee))
return createThis;
MCreateThis* createThis = MCreateThis::New(alloc(), callee);
MCreateThis* createThis = MCreateThis::New(alloc(), callee, newTarget);
current->add(createThis);
return createThis;
}
@ -6203,6 +6215,11 @@ IonBuilder::createThis(JSFunction* target, MDefinition* callee)
return magic;
}
if (target->isDerivedClassConstructor()) {
MOZ_ASSERT(target->isClassConstructor());
return constant(MagicValue(JS_UNINITIALIZED_LEXICAL));
}
// Try baking in the prototype.
if (MDefinition* createThis = createThisScriptedSingleton(target, callee))
return createThis;
@ -6210,7 +6227,7 @@ IonBuilder::createThis(JSFunction* target, MDefinition* callee)
if (MDefinition* createThis = createThisScriptedBaseline(callee))
return createThis;
return createThisScripted(callee);
return createThisScripted(callee, newTarget);
}
bool
@ -6600,7 +6617,7 @@ IonBuilder::makeCallHelper(JSFunction* target, CallInfo& callInfo)
// Inline the constructor on the caller-side.
if (callInfo.constructing()) {
MDefinition* create = createThis(target, callInfo.fun());
MDefinition* create = createThis(target, callInfo.fun(), callInfo.getNewTarget());
if (!create) {
abort("Failure inlining constructor for call.");
return nullptr;
@ -12749,10 +12766,22 @@ IonBuilder::jsop_this()
if (script()->strict() || info().funMaybeLazy()->isSelfHostedBuiltin()) {
// No need to wrap primitive |this| in strict mode or self-hosted code.
current->pushSlot(info().thisSlot());
MDefinition* thisVal = current->getSlot(info().thisSlot());
if (script()->isDerivedClassConstructor()) {
MOZ_ASSERT(info().funMaybeLazy()->isClassConstructor());
MOZ_ASSERT(script()->strict());
MLexicalCheck* checkThis = MLexicalCheck::New(alloc(), thisVal, Bailout_UninitializedThis);
current->add(checkThis);
thisVal = checkThis;
}
current->push(thisVal);
return true;
}
MOZ_ASSERT(!info().funMaybeLazy()->isClassConstructor());
if (thisTypes && (thisTypes->getKnownMIRType() == MIRType_Object ||
(thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject())))
{

View File

@ -380,10 +380,10 @@ class IonBuilder
JSObject* getSingletonPrototype(JSFunction* target);
MDefinition* createThisScripted(MDefinition* callee);
MDefinition* createThisScripted(MDefinition* callee, MDefinition* newTarget);
MDefinition* createThisScriptedSingleton(JSFunction* target, MDefinition* callee);
MDefinition* createThisScriptedBaseline(MDefinition* callee);
MDefinition* createThis(JSFunction* target, MDefinition* callee);
MDefinition* createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget);
MInstruction* createDeclEnvObject(MDefinition* callee, MDefinition* scopeObj);
MInstruction* createCallObject(MDefinition* callee, MDefinition* scopeObj);

View File

@ -111,8 +111,13 @@ enum BailoutKind
// We hit a |debugger;| statement.
Bailout_Debugger,
// END Normal bailouts
// |this| used uninitialized in a derived constructor
Bailout_UninitializedThis,
// Derived constructors must return object or undefined
Bailout_BadDerivedConstructorReturn,
// END Normal bailouts
// Bailouts caused by invalid assumptions based on Baseline code.
// Causes immediate invalidation.
@ -151,7 +156,7 @@ enum BailoutKind
Bailout_UninitializedLexical,
// A bailout to baseline from Ion on exception to handle Debugger hooks.
Bailout_IonExceptionDebugMode,
Bailout_IonExceptionDebugMode
};
inline const char*
@ -209,6 +214,10 @@ BailoutKindString(BailoutKind kind)
return "Bailout_InitialState";
case Bailout_Debugger:
return "Bailout_Debugger";
case Bailout_UninitializedThis:
return "Bailout_UninitializedThis";
case Bailout_BadDerivedConstructorReturn:
return "Bailout_BadDerivedConstructorReturn";
// Bailouts caused by invalid assumptions.
case Bailout_OverflowInvalidate:

View File

@ -328,6 +328,7 @@ LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto* ins)
{
LCreateThisWithProto* lir =
new(alloc()) LCreateThisWithProto(useRegisterOrConstantAtStart(ins->getCallee()),
useRegisterOrConstantAtStart(ins->getNewTarget()),
useRegisterOrConstantAtStart(ins->getPrototype()));
defineReturn(lir, ins);
assignSafepoint(lir, ins);
@ -336,7 +337,8 @@ LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto* ins)
void
LIRGenerator::visitCreateThis(MCreateThis* ins)
{
LCreateThis* lir = new(alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->getCallee()));
LCreateThis* lir = new(alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->getCallee()),
useRegisterOrConstantAtStart(ins->getNewTarget()));
defineReturn(lir, ins);
assignSafepoint(lir, ins);
}
@ -4258,7 +4260,7 @@ LIRGenerator::visitLexicalCheck(MLexicalCheck* ins)
MOZ_ASSERT(input->type() == MIRType_Value);
LLexicalCheck* lir = new(alloc()) LLexicalCheck();
useBox(lir, LLexicalCheck::Input, input);
assignSnapshot(lir, Bailout_UninitializedLexical);
assignSnapshot(lir, ins->bailoutKind());
add(lir, ins);
redefine(ins, input);
}
@ -4293,6 +4295,22 @@ LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree* ins)
define(new(alloc()) LAtomicIsLockFree(useRegister(ins->input())), ins);
}
void
LIRGenerator::visitCheckReturn(MCheckReturn* ins)
{
MDefinition* retVal = ins->returnValue();
MDefinition* thisVal = ins->thisValue();
MOZ_ASSERT(retVal->type() == MIRType_Value);
MOZ_ASSERT(thisVal->type() == MIRType_Value);
LCheckReturn* lir = new(alloc()) LCheckReturn();
useBoxAtStart(lir, LCheckReturn::ReturnValue, retVal);
useBoxAtStart(lir, LCheckReturn::ThisValue, thisVal);
assignSnapshot(lir, Bailout_BadDerivedConstructorReturn);
add(lir, ins);
redefine(ins, retVal);
}
static void
SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
{

View File

@ -306,6 +306,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitNewTarget(MNewTarget* ins);
void visitArrowNewTarget(MArrowNewTarget* ins);
void visitAtomicIsLockFree(MAtomicIsLockFree* ins);
void visitCheckReturn(MCheckReturn* ins);
};
} // namespace jit

View File

@ -4613,11 +4613,11 @@ class MCreateThisWithTemplate
// Caller-side allocation of |this| for |new|:
// Given a prototype operand, construct |this| for JSOP_NEW.
class MCreateThisWithProto
: public MBinaryInstruction,
public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
: public MTernaryInstruction,
public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >::Data
{
MCreateThisWithProto(MDefinition* callee, MDefinition* prototype)
: MBinaryInstruction(callee, prototype)
MCreateThisWithProto(MDefinition* callee, MDefinition* newTarget, MDefinition* prototype)
: MTernaryInstruction(callee, newTarget, prototype)
{
setResultType(MIRType_Object);
}
@ -4625,17 +4625,20 @@ class MCreateThisWithProto
public:
INSTRUCTION_HEADER(CreateThisWithProto)
static MCreateThisWithProto* New(TempAllocator& alloc, MDefinition* callee,
MDefinition* prototype)
MDefinition* newTarget, MDefinition* prototype)
{
return new(alloc) MCreateThisWithProto(callee, prototype);
return new(alloc) MCreateThisWithProto(callee, newTarget, prototype);
}
MDefinition* getCallee() const {
return getOperand(0);
}
MDefinition* getPrototype() const {
MDefinition* getNewTarget() const {
return getOperand(1);
}
MDefinition* getPrototype() const {
return getOperand(2);
}
// Although creation of |this| modifies global state, it is safely repeatable.
AliasSet getAliasSet() const override {
@ -4649,25 +4652,28 @@ class MCreateThisWithProto
// Caller-side allocation of |this| for |new|:
// Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
class MCreateThis
: public MUnaryInstruction,
public ObjectPolicy<0>::Data
: public MBinaryInstruction,
public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
{
explicit MCreateThis(MDefinition* callee)
: MUnaryInstruction(callee)
explicit MCreateThis(MDefinition* callee, MDefinition* newTarget)
: MBinaryInstruction(callee, newTarget)
{
setResultType(MIRType_Value);
}
public:
INSTRUCTION_HEADER(CreateThis)
static MCreateThis* New(TempAllocator& alloc, MDefinition* callee)
static MCreateThis* New(TempAllocator& alloc, MDefinition* callee, MDefinition* newTarget)
{
return new(alloc) MCreateThis(callee);
return new(alloc) MCreateThis(callee, newTarget);
}
MDefinition* getCallee() const {
return getOperand(0);
}
MDefinition* getNewTarget() const {
return getOperand(0);
}
// Although creation of |this| modifies global state, it is safely repeatable.
AliasSet getAliasSet() const override {
@ -7230,8 +7236,10 @@ class MLexicalCheck
: public MUnaryInstruction,
public BoxPolicy<0>::Data
{
explicit MLexicalCheck(MDefinition* input)
: MUnaryInstruction(input)
BailoutKind kind_;
explicit MLexicalCheck(MDefinition* input, BailoutKind kind)
: MUnaryInstruction(input),
kind_(kind)
{
setResultType(MIRType_Value);
setResultTypeSet(input->resultTypeSet());
@ -7242,8 +7250,9 @@ class MLexicalCheck
public:
INSTRUCTION_HEADER(LexicalCheck)
static MLexicalCheck* New(TempAllocator& alloc, MDefinition* input) {
return new(alloc) MLexicalCheck(input);
static MLexicalCheck* New(TempAllocator& alloc, MDefinition* input,
BailoutKind kind = Bailout_UninitializedLexical) {
return new(alloc) MLexicalCheck(input, kind);
}
AliasSet getAliasSet() const override {
@ -7254,6 +7263,10 @@ class MLexicalCheck
return getOperand(0);
}
BailoutKind bailoutKind() const {
return kind_;
}
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
@ -12936,6 +12949,33 @@ class MHasClass
}
};
class MCheckReturn
: public MBinaryInstruction,
public BoxInputsPolicy::Data
{
explicit MCheckReturn(MDefinition* retVal, MDefinition* thisVal)
: MBinaryInstruction(retVal, thisVal)
{
setGuard();
setResultType(MIRType_Value);
setResultTypeSet(retVal->resultTypeSet());
}
public:
INSTRUCTION_HEADER(CheckReturn)
static MCheckReturn* New(TempAllocator& alloc, MDefinition* retVal, MDefinition* thisVal) {
return new (alloc) MCheckReturn(retVal, thisVal);
}
MDefinition* returnValue() const {
return getOperand(0);
}
MDefinition* thisValue() const {
return getOperand(1);
}
};
// Increase the warm-up counter of the provided script upon execution and test if
// the warm-up counter surpasses the threshold. Upon hit it will recompile the
// outermost script (i.e. not the inlined script).

View File

@ -277,7 +277,8 @@ namespace jit {
_(GlobalNameConflictsCheck) \
_(Debugger) \
_(NewTarget) \
_(ArrowNewTarget)
_(ArrowNewTarget) \
_(CheckReturn)
// Forward declarations of MIR types.
#define FORWARD_DECLARE(op) class M##op;

View File

@ -1196,6 +1196,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
_(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >) \
_(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >) \
_(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2> >) \
_(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >) \
_(Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>) \
_(Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >) \
_(Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >) \

View File

@ -565,7 +565,7 @@ GetIntrinsicValue(JSContext* cx, HandlePropertyName name, MutableHandleValue rva
}
bool
CreateThis(JSContext* cx, HandleObject callee, MutableHandleValue rval)
CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval)
{
rval.set(MagicValue(JS_IS_CONSTRUCTING));
@ -575,10 +575,14 @@ CreateThis(JSContext* cx, HandleObject callee, MutableHandleValue rval)
JSScript* script = fun->getOrCreateScript(cx);
if (!script || !script->ensureHasTypes(cx))
return false;
JSObject* thisObj = CreateThisForFunction(cx, callee, GenericObject);
if (!thisObj)
return false;
rval.set(ObjectValue(*thisObj));
if (script->isDerivedClassConstructor()) {
rval.set(MagicValue(JS_UNINITIALIZED_LEXICAL));
} else {
JSObject* thisObj = CreateThisForFunction(cx, callee, newTarget, GenericObject);
if (!thisObj)
return false;
rval.set(ObjectValue(*thisObj));
}
}
}
@ -1291,5 +1295,18 @@ ThrowUninitializedLexical(JSContext* cx)
return false;
}
bool
ThrowBadDerivedReturn(JSContext* cx, HandleValue v)
{
ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, v, nullptr);
return false;
}
bool
BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame)
{
return ThrowUninitializedThis(cx, frame);
}
} // namespace jit
} // namespace js

View File

@ -634,7 +634,7 @@ bool OperatorInI(JSContext* cx, uint32_t index, HandleObject obj, bool* out);
bool GetIntrinsicValue(JSContext* cx, HandlePropertyName name, MutableHandleValue rval);
bool CreateThis(JSContext* cx, HandleObject callee, MutableHandleValue rval);
bool CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval);
void GetDynamicName(JSContext* cx, JSObject* scopeChain, JSString* str, Value* vp);
@ -734,6 +734,8 @@ IonMarkFunction(MIRType type)
bool ObjectIsCallable(JSObject* obj);
bool ThrowUninitializedLexical(JSContext* cx);
bool BaselineThrowUninitializedThis(JSContext* cx, BaselineFrame* frame);
bool ThrowBadDerivedReturn(JSContext* cx, HandleValue v);
} // namespace jit
} // namespace js

View File

@ -13,6 +13,7 @@
#include "jit/arm64/vixl/Debugger-vixl.h"
#endif
#include "jit/MacroAssembler-inl.h"
using namespace js;
using namespace js::jit;

View File

@ -5,10 +5,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/arm64/MoveEmitter-arm64.h"
#include "jit/MacroAssembler-inl.h"
using namespace js;
using namespace js::jit;
MemOperand
MoveEmitterARM64::toMemOperand(const MoveOperand& operand) const
{
MOZ_ASSERT(operand.isMemory());
ARMRegister base(operand.base(), 64);
if (operand.base() == masm.getStackPointer())
return MemOperand(base, operand.disp() + (masm.framePushed() - pushedAtStart_));
return MemOperand(base, operand.disp());
}
void
MoveEmitterARM64::emit(const MoveResolver& moves)
{

View File

@ -35,13 +35,7 @@ class MoveEmitterARM64
}
MemOperand cycleSlot();
MemOperand toMemOperand(const MoveOperand& operand) const {
MOZ_ASSERT(operand.isMemory());
ARMRegister base(operand.base(), 64);
if (operand.base() == masm.getStackPointer())
return MemOperand(base, operand.disp() + (masm.framePushed() - pushedAtStart_));
return MemOperand(base, operand.disp());
}
MemOperand toMemOperand(const MoveOperand& operand) const;
ARMRegister toARMReg32(const MoveOperand& operand) const {
MOZ_ASSERT(operand.isGeneralReg());
return ARMRegister(operand.reg(), 32);

View File

@ -256,7 +256,7 @@ const Instruction* Instruction::ImmPCOffsetTarget() const {
}
inline int Instruction::ImmBranch() const {
int Instruction::ImmBranch() const {
switch (BranchType()) {
case CondBranchType: return ImmCondBranch();
case UncondBranchType: return ImmUncondBranch();

View File

@ -1300,19 +1300,23 @@ class LToIdV : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 1>
// Allocate an object for |new| on the caller-side,
// when there is no templateObject or prototype known
class LCreateThis : public LCallInstructionHelper<BOX_PIECES, 1, 0>
class LCreateThis : public LCallInstructionHelper<BOX_PIECES, 2, 0>
{
public:
LIR_HEADER(CreateThis)
explicit LCreateThis(const LAllocation& callee)
LCreateThis(const LAllocation& callee, const LAllocation& newTarget)
{
setOperand(0, callee);
setOperand(1, newTarget);
}
const LAllocation* getCallee() {
return getOperand(0);
}
const LAllocation* getNewTarget() {
return getOperand(1);
}
MCreateThis* mir() const {
return mir_->toCreateThis();
@ -1321,23 +1325,28 @@ class LCreateThis : public LCallInstructionHelper<BOX_PIECES, 1, 0>
// Allocate an object for |new| on the caller-side,
// when the prototype is known.
class LCreateThisWithProto : public LCallInstructionHelper<1, 2, 0>
class LCreateThisWithProto : public LCallInstructionHelper<1, 3, 0>
{
public:
LIR_HEADER(CreateThisWithProto)
LCreateThisWithProto(const LAllocation& callee, const LAllocation& prototype)
LCreateThisWithProto(const LAllocation& callee, const LAllocation& newTarget,
const LAllocation& prototype)
{
setOperand(0, callee);
setOperand(1, prototype);
setOperand(1, newTarget);
setOperand(2, prototype);
}
const LAllocation* getCallee() {
return getOperand(0);
}
const LAllocation* getPrototype() {
const LAllocation* getNewTarget() {
return getOperand(1);
}
const LAllocation* getPrototype() {
return getOperand(2);
}
MCreateThis* mir() const {
return mir_->toCreateThis();
@ -7247,6 +7256,15 @@ class LRandom : public LInstructionHelper<1, 0, LRANDOM_NUM_TEMPS>
}
};
class LCheckReturn : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0>
{
public:
static const size_t ReturnValue = 0;
static const size_t ThisValue = BOX_PIECES;
LIR_HEADER(CheckReturn)
};
} // namespace jit
} // namespace js

View File

@ -368,6 +368,7 @@
_(GlobalNameConflictsCheck) \
_(Debugger) \
_(NewTarget) \
_(ArrowNewTarget)
_(ArrowNewTarget) \
_(CheckReturn)
#endif /* jit_shared_LOpcodes_shared_h */

View File

@ -106,6 +106,8 @@ MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeo
MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not an object or null")
MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|")
MSG_DEF(JSMSG_DISABLED_DERIVED_CLASS, 1, JSEXN_INTERNALERR, "{0} temporarily disallowed in derived class constructors")
MSG_DEF(JSMSG_UNINITIALIZED_THIS, 1, JSEXN_REFERENCEERR, "|this| used uninitialized in {0} class constructor")
MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}")
// JSON
MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")
@ -212,6 +214,7 @@ MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "can't assign to {0}
MSG_DEF(JSMSG_BAD_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement")
MSG_DEF(JSMSG_BAD_SUPER, 0, JSEXN_SYNTAXERR, "invalid use of keyword 'super'")
MSG_DEF(JSMSG_BAD_SUPERPROP, 1, JSEXN_SYNTAXERR, "use of super {0} accesses only valid within methods or eval code within methods")
MSG_DEF(JSMSG_BAD_SUPERCALL, 0, JSEXN_SYNTAXERR, "super() is only valid in derived class constructors")
MSG_DEF(JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION, 0, JSEXN_SYNTAXERR, "missing ] after array comprehension")
MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing ] after element list")
MSG_DEF(JSMSG_BRACKET_IN_INDEX, 0, JSEXN_SYNTAXERR, "missing ] in index expression")
@ -507,6 +510,7 @@ MSG_DEF(JSMSG_NO_INDEXED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have an
// Super
MSG_DEF(JSMSG_CANT_DELETE_SUPER, 0, JSEXN_REFERENCEERR, "invalid delete involving 'super'")
MSG_DEF(JSMSG_REINIT_THIS, 0, JSEXN_REFERENCEERR, "super() called twice in derived class constructor")
// Modules
MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT, 0, JSEXN_SYNTAXERR, "default export cannot be provided by export *")

View File

@ -6390,6 +6390,12 @@ JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length)
return funobj;
}
JS_PUBLIC_API(bool)
JS_SetImmutablePrototype(JSContext *cx, JS::HandleObject obj, bool *succeeded)
{
return SetImmutablePrototype(cx, obj, succeeded);
}
JS_PUBLIC_API(void)
JS::SetAsmJSCacheOps(JSRuntime* rt, const JS::AsmJSCacheOps* ops)
{

View File

@ -2462,6 +2462,16 @@ JS_FreezeObject(JSContext* cx, JS::Handle<JSObject*> obj);
extern JS_PUBLIC_API(bool)
JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
/*
* Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt
* to modify it will fail. If an error occurs during the attempt, return false
* (with a pending exception set, depending upon the nature of the error). If
* no error occurs, return true with |*succeeded| set to indicate whether the
* attempt successfully made the [[Prototype]] immutable.
*/
extern JS_PUBLIC_API(bool)
JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded);
extern JS_PUBLIC_API(JSObject*)
JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args);

View File

@ -374,6 +374,12 @@ struct JSCompartment
js::NewObjectMetadataState objectMetadataState;
public:
// Recompute the probability with which this compartment should record
// profiling data (stack traces, allocations log, etc.) about each
// allocation. We consult the probabilities requested by the Debugger
// instances observing us, if any.
void chooseAllocationSamplingProbability() { savedStacks_.chooseSamplingProbability(this); }
bool hasObjectPendingMetadata() const { return objectMetadataState.is<js::PendingMetadata>(); }
void setObjectPendingMetadata(JSContext* cx, JSObject* obj) {

View File

@ -156,6 +156,7 @@ class JSFunction : public js::NativeObject
nonLazyScript()->funHasExtensibleScope() ||
nonLazyScript()->funNeedsDeclEnvObject() ||
nonLazyScript()->needsHomeObject() ||
nonLazyScript()->isDerivedClassConstructor() ||
isGenerator();
}
@ -516,6 +517,16 @@ class JSFunction : public js::NativeObject
u.n.jitinfo = data;
}
bool isDerivedClassConstructor() {
bool derived;
if (isInterpretedLazy())
derived = lazyScript()->isDerivedClassConstructor();
else
derived = nonLazyScript()->isDerivedClassConstructor();
MOZ_ASSERT_IF(derived, isClassConstructor());
return derived;
}
static unsigned offsetOfNativeOrScript() {
static_assert(offsetof(U, n.native) == offsetof(U, i.s.script_),
"native and script pointers must be in the same spot "

View File

@ -734,15 +734,11 @@ js::math_pow(JSContext* cx, unsigned argc, Value* vp)
return math_pow_handle(cx, args.get(0), args.get(1), args.rval());
}
static uint64_t
random_generateSeed()
void
js::random_generateSeed(uint64_t* seedBuffer, size_t length)
{
union {
uint8_t u8[8];
uint32_t u32[2];
uint64_t u64;
} seed;
seed.u64 = 0;
if (length == 0)
return;
#if defined(XP_WIN)
/*
@ -760,6 +756,12 @@ random_generateSeed()
if (oldWay && !newWay)
MOZ_CRASH();
union {
uint32_t u32[2];
uint64_t u64;
} seed;
seed.u64 = 0;
errno_t error = rand_s(&seed.u32[0]);
if (oldWay)
@ -771,24 +773,44 @@ random_generateSeed()
error = rand_s(&seed.u32[1]);
MOZ_ASSERT(error == 0, "rand_s() error?!");
seedBuffer[0] = seed.u64 ^= PRMJ_Now();
for (size_t i = 1; i < length; i++) {
error = rand_s(&seed.u32[0]);
MOZ_ASSERT(error == 0, "rand_s() error?!");
error = rand_s(&seed.u32[1]);
MOZ_ASSERT(error == 0, "rand_s() error?!");
seedBuffer[i] = seed.u64 ^ PRMJ_Now();
}
#elif defined(HAVE_ARC4RANDOM)
seed.u32[0] = arc4random();
seed.u32[1] = arc4random();
union {
uint32_t u32[2];
uint64_t u64;
} seed;
seed.u64 = 0;
for (size_t i = 0; i < length; i++) {
seed.u32[0] = arc4random();
seed.u32[1] = arc4random();
seedBuffer[i] = seed.u64 ^ PRMJ_Now();
}
#elif defined(XP_UNIX)
int fd = open("/dev/urandom", O_RDONLY);
MOZ_ASSERT(fd >= 0, "Can't open /dev/urandom?!");
if (fd >= 0) {
ssize_t nread = read(fd, seed.u8, mozilla::ArrayLength(seed.u8));
MOZ_ASSERT(nread == 8, "Can't read /dev/urandom?!");
ssize_t size = length * sizeof(seedBuffer[0]);
ssize_t nread = read(fd, (char *) seedBuffer, size);
MOZ_ASSERT(nread == size, "Can't read /dev/urandom?!");
mozilla::unused << nread;
close(fd);
}
#else
# error "Platform needs to implement random_generateSeed()"
#endif
seed.u64 ^= PRMJ_Now();
return seed.u64;
}
/*
@ -798,7 +820,8 @@ void
js::random_initState(uint64_t* rngState)
{
/* Our PRNG only uses 48 bits, so squeeze our entropy into those bits. */
uint64_t seed = random_generateSeed();
uint64_t seed;
random_generateSeed(&seed, 1);
seed ^= (seed >> 16);
*rngState = (seed ^ RNG_MULTIPLIER) & RNG_MASK;
}

View File

@ -109,6 +109,13 @@ class MathCache
extern JSObject*
InitMathClass(JSContext* cx, HandleObject obj);
/*
* Fill |seed[0]| through |seed[length-1]| with random bits, suitable for
* seeding a random number generator.
*/
extern void
random_generateSeed(uint64_t* seed, size_t length);
extern void
random_initState(uint64_t* rngState);

View File

@ -967,14 +967,14 @@ CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group,
}
JSObject*
js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObject proto,
NewObjectKind newKind /* = GenericObject */)
js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObject newTarget,
HandleObject proto, NewObjectKind newKind /* = GenericObject */)
{
RootedObject res(cx);
if (proto) {
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto),
&callee->as<JSFunction>()));
newTarget));
if (!group)
return nullptr;
@ -986,7 +986,7 @@ js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObj
// The script was analyzed successfully and may have changed
// the new type table, so refetch the group.
group = ObjectGroup::defaultNewGroup(cx, nullptr, TaggedProto(proto),
&callee->as<JSFunction>());
newTarget);
MOZ_ASSERT(group && group->newScript());
}
}
@ -1007,15 +1007,16 @@ js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObj
}
JSObject*
js::CreateThisForFunction(JSContext* cx, HandleObject callee, NewObjectKind newKind)
js::CreateThisForFunction(JSContext* cx, HandleObject callee, HandleObject newTarget,
NewObjectKind newKind)
{
RootedValue protov(cx);
if (!GetProperty(cx, callee, callee, cx->names().prototype, &protov))
if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov))
return nullptr;
RootedObject proto(cx);
if (protov.isObject())
proto = &protov.toObject();
JSObject* obj = CreateThisForFunctionWithProto(cx, callee, proto, newKind);
JSObject* obj = CreateThisForFunctionWithProto(cx, callee, newTarget, proto, newKind);
if (obj && newKind == SingletonObject) {
RootedPlainObject nobj(cx, &obj->as<PlainObject>());
@ -2394,7 +2395,7 @@ JSObject::reportNotExtensible(JSContext* cx, unsigned report)
// immutable-prototype behavior is enforced; if it's false, behavior is not
// enforced, and immutable-prototype bits stored on objects are completely
// ignored.
static const bool ImmutablePrototypesEnabled = true;
static const bool ImmutablePrototypesEnabled = false;
JS_FRIEND_API(bool)
JS_ImmutablePrototypesEnabled()
@ -3340,6 +3341,7 @@ JSObject::dump()
if (obj->hasUncacheableProto()) fprintf(stderr, " has_uncacheable_proto");
if (obj->hadElementsAccess()) fprintf(stderr, " had_elements_access");
if (obj->wasNewScriptCleared()) fprintf(stderr, " new_script_cleared");
if (!obj->hasLazyPrototype() && obj->nonLazyPrototypeIsImmutable()) fprintf(stderr, " immutable_prototype");
if (obj->isNative()) {
NativeObject* nobj = &obj->as<NativeObject>();

View File

@ -1162,12 +1162,13 @@ GetInitialHeap(NewObjectKind newKind, const Class* clasp)
// Specialized call for constructing |this| with a known function callee,
// and a known prototype.
extern JSObject*
CreateThisForFunctionWithProto(JSContext* cx, js::HandleObject callee, HandleObject proto,
NewObjectKind newKind = GenericObject);
CreateThisForFunctionWithProto(JSContext* cx, js::HandleObject callee, HandleObject newTarget,
HandleObject proto, NewObjectKind newKind = GenericObject);
// Specialized call for constructing |this| with a known function callee.
extern JSObject*
CreateThisForFunction(JSContext* cx, js::HandleObject callee, NewObjectKind newKind);
CreateThisForFunction(JSContext* cx, js::HandleObject callee, js::HandleObject newTarget,
NewObjectKind newKind);
// Generic call for constructing |this|.
extern JSObject*

View File

@ -125,6 +125,7 @@ js::StackUses(JSScript* script, jsbytecode* pc)
case JSOP_POPN:
return GET_UINT16(pc);
case JSOP_NEW:
case JSOP_SUPERCALL:
return 2 + GET_ARGC(pc) + 1;
default:
/* stack: fun, this, [argc arguments] */

View File

@ -109,30 +109,53 @@ enum JSShellExitCode {
EXITCODE_TIMEOUT = 6
};
static size_t gStackChunkSize = 8192;
static const size_t gStackChunkSize = 8192;
/*
* Note: This limit should match the stack limit set by the browser in
* js/xpconnect/src/XPCJSRuntime.cpp
*/
#if defined(MOZ_ASAN) || (defined(DEBUG) && !defined(XP_WIN))
static size_t gMaxStackSize = 2 * 128 * sizeof(size_t) * 1024;
static const size_t gMaxStackSize = 2 * 128 * sizeof(size_t) * 1024;
#else
static size_t gMaxStackSize = 128 * sizeof(size_t) * 1024;
static const size_t gMaxStackSize = 128 * sizeof(size_t) * 1024;
#endif
/*
* Limit the timeout to 30 minutes to prevent an overflow on platfoms
* that represent the time internally in microseconds using 32-bit int.
*/
static double MAX_TIMEOUT_INTERVAL = 1800.0;
static double gTimeoutInterval = -1.0;
static Atomic<bool> gServiceInterrupt;
static JS::PersistentRootedValue gInterruptFunc;
static const double MAX_TIMEOUT_INTERVAL = 1800.0;
static bool gLastWarningEnabled = false;
static JS::PersistentRootedValue gLastWarning;
// Per-runtime shell state.
struct ShellRuntime
{
ShellRuntime();
bool isWorker;
double timeoutInterval;
Atomic<bool> serviceInterrupt;
JS::PersistentRootedValue interruptFunc;
bool lastWarningEnabled;
JS::PersistentRootedValue lastWarning;
/*
* Watchdog thread state.
*/
PRLock* watchdogLock;
PRCondVar* watchdogWakeup;
PRThread* watchdogThread;
bool watchdogHasTimeout;
int64_t watchdogTimeout;
PRCondVar* sleepWakeup;
int exitCode;
bool quitting;
bool gotError;
};
// Shell state set once at startup.
static bool enableCodeCoverage = false;
static bool enableDisassemblyDumps = false;
static bool offthreadCompilation = false;
@ -144,11 +167,22 @@ static bool enableUnboxedArrays = false;
#ifdef JS_GC_ZEAL
static char gZealStr[128];
#endif
static bool printTiming = false;
static const char* jsCacheDir = nullptr;
static const char* jsCacheAsmJSPath = nullptr;
static bool jsCachingEnabled = false;
static FILE* gErrFile = nullptr;
static FILE* gOutFile = nullptr;
static bool reportWarnings = true;
static bool compileOnly = false;
static bool fuzzingSafe = false;
static bool disableOOMFunctions = false;
#ifdef DEBUG
static bool dumpEntrainedVariables = false;
static bool OOM_printAllocationCount = false;
#endif
// Shell state this is only accessed on the main thread.
bool jsCachingEnabled = false;
mozilla::Atomic<bool> jsCacheOpened(false);
static bool
@ -158,7 +192,7 @@ static bool
InitWatchdog(JSRuntime* rt);
static void
KillWatchdog();
KillWatchdog(JSRuntime *rt);
static bool
ScheduleWatchdog(JSRuntime* rt, double t);
@ -166,33 +200,6 @@ ScheduleWatchdog(JSRuntime* rt, double t);
static void
CancelExecution(JSRuntime* rt);
/*
* Watchdog thread state.
*/
static PRLock* gWatchdogLock = nullptr;
static PRCondVar* gWatchdogWakeup = nullptr;
static PRThread* gWatchdogThread = nullptr;
static bool gWatchdogHasTimeout = false;
static int64_t gWatchdogTimeout = 0;
static PRCondVar* gSleepWakeup = nullptr;
static int gExitCode = 0;
static bool gQuitting = false;
static bool gGotError = false;
static FILE* gErrFile = nullptr;
static FILE* gOutFile = nullptr;
static bool reportWarnings = true;
static bool compileOnly = false;
static bool fuzzingSafe = false;
static bool disableOOMFunctions = false;
#ifdef DEBUG
static bool dumpEntrainedVariables = false;
static bool OOM_printAllocationCount = false;
#endif
static JSContext*
NewContext(JSRuntime* rt);
@ -267,6 +274,36 @@ extern JS_EXPORT_API(void) add_history(char* line);
} // extern "C"
#endif
ShellRuntime::ShellRuntime()
: isWorker(false),
timeoutInterval(-1.0),
serviceInterrupt(false),
lastWarningEnabled(false),
watchdogLock(nullptr),
watchdogWakeup(nullptr),
watchdogThread(nullptr),
watchdogHasTimeout(false),
watchdogTimeout(0),
sleepWakeup(nullptr),
exitCode(0),
quitting(false),
gotError(false)
{}
static ShellRuntime*
GetShellRuntime(JSRuntime *rt)
{
ShellRuntime* sr = static_cast<ShellRuntime*>(JS_GetRuntimePrivate(rt));
MOZ_ASSERT(sr);
return sr;
}
static ShellRuntime*
GetShellRuntime(JSContext* cx)
{
return GetShellRuntime(cx->runtime());
}
static char*
GetLine(FILE* file, const char * prompt)
{
@ -370,17 +407,18 @@ GetContextData(JSContext* cx)
static bool
ShellInterruptCallback(JSContext* cx)
{
if (!gServiceInterrupt)
ShellRuntime* sr = GetShellRuntime(cx);
if (!sr->serviceInterrupt)
return true;
// Reset gServiceInterrupt. CancelExecution or InterruptIf will set it to
// Reset serviceInterrupt. CancelExecution or InterruptIf will set it to
// true to distinguish watchdog or user triggered interrupts.
// Do this first to prevent other interrupts that may occur while the
// user-supplied callback is executing from re-entering the handler.
gServiceInterrupt = false;
sr->serviceInterrupt = false;
bool result;
RootedValue interruptFunc(cx, gInterruptFunc);
RootedValue interruptFunc(cx, sr->interruptFunc);
if (!interruptFunc.isNull()) {
JS::AutoSaveExceptionState savedExc(cx);
JSAutoCompartment ac(cx, &interruptFunc.toObject());
@ -398,8 +436,8 @@ ShellInterruptCallback(JSContext* cx)
result = false;
}
if (!result && gExitCode == 0)
gExitCode = EXITCODE_TIMEOUT;
if (!result && sr->exitCode == 0)
sr->exitCode = EXITCODE_TIMEOUT;
return result;
}
@ -432,6 +470,8 @@ SkipUTF8BOM(FILE* file)
static void
RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
{
ShellRuntime* sr = GetShellRuntime(cx);
SkipUTF8BOM(file);
// To support the UNIX #! shell hack, gobble the first line if it starts
@ -456,9 +496,9 @@ RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
.setIsRunOnce(true)
.setNoScriptRval(true);
gGotError = false;
sr->gotError = false;
(void) JS::Compile(cx, options, file, &script);
MOZ_ASSERT_IF(!script, gGotError);
MOZ_ASSERT_IF(!script, sr->gotError);
}
#ifdef DEBUG
@ -467,8 +507,8 @@ RunFile(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
#endif
if (script && !compileOnly) {
if (!JS_ExecuteScript(cx, script)) {
if (!gQuitting && gExitCode != EXITCODE_TIMEOUT)
gExitCode = EXITCODE_RUNTIME_ERROR;
if (!sr->quitting && sr->exitCode != EXITCODE_TIMEOUT)
sr->exitCode = EXITCODE_RUNTIME_ERROR;
}
int64_t t2 = PRMJ_Now() - t1;
if (printTiming)
@ -514,6 +554,7 @@ EvalAndPrint(JSContext* cx, const char* bytes, size_t length,
static void
ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
{
ShellRuntime* sr = GetShellRuntime(cx);
int lineno = 1;
bool hitEOF = false;
@ -529,7 +570,7 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
CharBuffer buffer(cx);
do {
ScheduleWatchdog(cx->runtime(), -1);
gServiceInterrupt = false;
sr->serviceInterrupt = false;
errno = 0;
char* line = GetLine(in, startline == lineno ? "js> " : "");
@ -546,7 +587,7 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
return;
lineno++;
if (!ScheduleWatchdog(cx->runtime(), gTimeoutInterval)) {
if (!ScheduleWatchdog(cx->runtime(), sr->timeoutInterval)) {
hitEOF = true;
break;
}
@ -561,7 +602,7 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
// Catch the error, report it, and keep going.
JS_ReportPendingException(cx);
}
} while (!hitEOF && !gQuitting);
} while (!hitEOF && !sr->quitting);
fprintf(out, "\n");
}
@ -1543,6 +1584,8 @@ Help(JSContext* cx, unsigned argc, Value* vp);
static bool
Quit(JSContext* cx, unsigned argc, Value* vp)
{
ShellRuntime* sr = GetShellRuntime(cx);
#ifdef JS_MORE_DETERMINISTIC
// Print a message to stderr in more-deterministic builds to help jsfunfuzz
// find uncatchable-exception bugs.
@ -1564,8 +1607,8 @@ Quit(JSContext* cx, unsigned argc, Value* vp)
return false;
}
gExitCode = code;
gQuitting = true;
sr->exitCode = code;
sr->quitting = true;
return false;
}
@ -2545,9 +2588,25 @@ WorkerMain(void* arg)
js_delete(input);
return;
}
mozilla::UniquePtr<ShellRuntime> sr = MakeUnique<ShellRuntime>();
if (!sr) {
JS_DestroyRuntime(rt);
js_delete(input);
return;
}
sr->isWorker = true;
JS_SetRuntimePrivate(rt, sr.get());
JS_SetErrorReporter(rt, my_ErrorReporter);
SetWorkerRuntimeOptions(rt);
if (!InitWatchdog(rt)) {
JS_DestroyRuntime(rt);
js_delete(input);
return;
}
JSContext* cx = NewContext(rt);
if (!cx) {
JS_DestroyRuntime(rt);
@ -2653,6 +2712,7 @@ IsBefore(int64_t t1, int64_t t2)
static bool
Sleep_fn(JSContext* cx, unsigned argc, Value* vp)
{
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp);
int64_t t_ticks;
@ -2673,61 +2733,63 @@ Sleep_fn(JSContext* cx, unsigned argc, Value* vp)
? 0
: int64_t(PRMJ_USEC_PER_SEC * t_secs);
}
PR_Lock(gWatchdogLock);
PR_Lock(sr->watchdogLock);
int64_t to_wakeup = PRMJ_Now() + t_ticks;
for (;;) {
PR_WaitCondVar(gSleepWakeup, PR_MillisecondsToInterval(t_ticks / 1000));
if (gServiceInterrupt)
PR_WaitCondVar(sr->sleepWakeup, PR_MillisecondsToInterval(t_ticks / 1000));
if (sr->serviceInterrupt)
break;
int64_t now = PRMJ_Now();
if (!IsBefore(now, to_wakeup))
break;
t_ticks = to_wakeup - now;
}
PR_Unlock(gWatchdogLock);
PR_Unlock(sr->watchdogLock);
args.rval().setUndefined();
return !gServiceInterrupt;
return !sr->serviceInterrupt;
}
static bool
InitWatchdog(JSRuntime* rt)
{
MOZ_ASSERT(!gWatchdogThread);
gWatchdogLock = PR_NewLock();
if (gWatchdogLock) {
gWatchdogWakeup = PR_NewCondVar(gWatchdogLock);
if (gWatchdogWakeup) {
gSleepWakeup = PR_NewCondVar(gWatchdogLock);
if (gSleepWakeup)
ShellRuntime* sr = GetShellRuntime(rt);
MOZ_ASSERT(!sr->watchdogThread);
sr->watchdogLock = PR_NewLock();
if (sr->watchdogLock) {
sr->watchdogWakeup = PR_NewCondVar(sr->watchdogLock);
if (sr->watchdogWakeup) {
sr->sleepWakeup = PR_NewCondVar(sr->watchdogLock);
if (sr->sleepWakeup)
return true;
PR_DestroyCondVar(gWatchdogWakeup);
PR_DestroyCondVar(sr->watchdogWakeup);
}
PR_DestroyLock(gWatchdogLock);
PR_DestroyLock(sr->watchdogLock);
}
return false;
}
static void
KillWatchdog()
KillWatchdog(JSRuntime* rt)
{
ShellRuntime* sr = GetShellRuntime(rt);
PRThread* thread;
PR_Lock(gWatchdogLock);
thread = gWatchdogThread;
PR_Lock(sr->watchdogLock);
thread = sr->watchdogThread;
if (thread) {
/*
* The watchdog thread is running, tell it to terminate waking it up
* if necessary.
*/
gWatchdogThread = nullptr;
PR_NotifyCondVar(gWatchdogWakeup);
sr->watchdogThread = nullptr;
PR_NotifyCondVar(sr->watchdogWakeup);
}
PR_Unlock(gWatchdogLock);
PR_Unlock(sr->watchdogLock);
if (thread)
PR_JoinThread(thread);
PR_DestroyCondVar(gSleepWakeup);
PR_DestroyCondVar(gWatchdogWakeup);
PR_DestroyLock(gWatchdogLock);
PR_DestroyCondVar(sr->sleepWakeup);
PR_DestroyCondVar(sr->watchdogWakeup);
PR_DestroyLock(sr->watchdogLock);
}
static void
@ -2736,24 +2798,25 @@ WatchdogMain(void* arg)
PR_SetCurrentThreadName("JS Watchdog");
JSRuntime* rt = (JSRuntime*) arg;
ShellRuntime* sr = GetShellRuntime(rt);
PR_Lock(gWatchdogLock);
while (gWatchdogThread) {
PR_Lock(sr->watchdogLock);
while (sr->watchdogThread) {
int64_t now = PRMJ_Now();
if (gWatchdogHasTimeout && !IsBefore(now, gWatchdogTimeout)) {
if (sr->watchdogHasTimeout && !IsBefore(now, sr->watchdogTimeout)) {
/*
* The timeout has just expired. Request an interrupt callback
* outside the lock.
*/
gWatchdogHasTimeout = false;
PR_Unlock(gWatchdogLock);
sr->watchdogHasTimeout = false;
PR_Unlock(sr->watchdogLock);
CancelExecution(rt);
PR_Lock(gWatchdogLock);
PR_Lock(sr->watchdogLock);
/* Wake up any threads doing sleep. */
PR_NotifyAllCondVar(gSleepWakeup);
PR_NotifyAllCondVar(sr->sleepWakeup);
} else {
if (gWatchdogHasTimeout) {
if (sr->watchdogHasTimeout) {
/*
* Time hasn't expired yet. Simulate an interrupt callback
* which doesn't abort execution.
@ -2762,58 +2825,61 @@ WatchdogMain(void* arg)
}
uint64_t sleepDuration = PR_INTERVAL_NO_TIMEOUT;
if (gWatchdogHasTimeout)
if (sr->watchdogHasTimeout)
sleepDuration = PR_TicksPerSecond() / 10;
mozilla::DebugOnly<PRStatus> status =
PR_WaitCondVar(gWatchdogWakeup, sleepDuration);
PR_WaitCondVar(sr->watchdogWakeup, sleepDuration);
MOZ_ASSERT(status == PR_SUCCESS);
}
}
PR_Unlock(gWatchdogLock);
PR_Unlock(sr->watchdogLock);
}
static bool
ScheduleWatchdog(JSRuntime* rt, double t)
{
ShellRuntime* sr = GetShellRuntime(rt);
if (t <= 0) {
PR_Lock(gWatchdogLock);
gWatchdogHasTimeout = false;
PR_Unlock(gWatchdogLock);
PR_Lock(sr->watchdogLock);
sr->watchdogHasTimeout = false;
PR_Unlock(sr->watchdogLock);
return true;
}
int64_t interval = int64_t(ceil(t * PRMJ_USEC_PER_SEC));
int64_t timeout = PRMJ_Now() + interval;
PR_Lock(gWatchdogLock);
if (!gWatchdogThread) {
MOZ_ASSERT(!gWatchdogHasTimeout);
gWatchdogThread = PR_CreateThread(PR_USER_THREAD,
PR_Lock(sr->watchdogLock);
if (!sr->watchdogThread) {
MOZ_ASSERT(!sr->watchdogHasTimeout);
sr->watchdogThread = PR_CreateThread(PR_USER_THREAD,
WatchdogMain,
rt,
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD,
0);
if (!gWatchdogThread) {
PR_Unlock(gWatchdogLock);
if (!sr->watchdogThread) {
PR_Unlock(sr->watchdogLock);
return false;
}
} else if (!gWatchdogHasTimeout || IsBefore(timeout, gWatchdogTimeout)) {
PR_NotifyCondVar(gWatchdogWakeup);
} else if (!sr->watchdogHasTimeout || IsBefore(timeout, sr->watchdogTimeout)) {
PR_NotifyCondVar(sr->watchdogWakeup);
}
gWatchdogHasTimeout = true;
gWatchdogTimeout = timeout;
PR_Unlock(gWatchdogLock);
sr->watchdogHasTimeout = true;
sr->watchdogTimeout = timeout;
PR_Unlock(sr->watchdogLock);
return true;
}
static void
CancelExecution(JSRuntime* rt)
{
gServiceInterrupt = true;
ShellRuntime* sr = GetShellRuntime(rt);
sr->serviceInterrupt = true;
JS_RequestInterruptCallback(rt);
if (!gInterruptFunc.isNull()) {
if (!sr->interruptFunc.isNull()) {
static const char msg[] = "Script runs for too long, terminating.\n";
fputs(msg, stderr);
}
@ -2827,7 +2893,7 @@ SetTimeoutValue(JSContext* cx, double t)
JS_ReportError(cx, "Excessive timeout value");
return false;
}
gTimeoutInterval = t;
GetShellRuntime(cx)->timeoutInterval = t;
if (!ScheduleWatchdog(cx->runtime(), t)) {
JS_ReportError(cx, "Failed to create the watchdog");
return false;
@ -2838,10 +2904,11 @@ SetTimeoutValue(JSContext* cx, double t)
static bool
Timeout(JSContext* cx, unsigned argc, Value* vp)
{
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() == 0) {
args.rval().setNumber(gTimeoutInterval);
args.rval().setNumber(sr->timeoutInterval);
return true;
}
@ -2860,7 +2927,7 @@ Timeout(JSContext* cx, unsigned argc, Value* vp)
JS_ReportError(cx, "Second argument must be a timeout function");
return false;
}
gInterruptFunc = value;
sr->interruptFunc = value;
}
args.rval().setUndefined();
@ -2878,7 +2945,7 @@ InterruptIf(JSContext* cx, unsigned argc, Value* vp)
}
if (ToBoolean(args[0])) {
gServiceInterrupt = true;
GetShellRuntime(cx)->serviceInterrupt = true;
JS_RequestInterruptCallback(cx->runtime());
}
@ -2895,7 +2962,7 @@ InvokeInterruptCallbackWrapper(JSContext* cx, unsigned argc, Value* vp)
return false;
}
gServiceInterrupt = true;
GetShellRuntime(cx)->serviceInterrupt = true;
JS_RequestInterruptCallback(cx->runtime());
bool interruptRv = CheckForInterrupt(cx);
@ -2931,7 +2998,7 @@ SetInterruptCallback(JSContext* cx, unsigned argc, Value* vp)
JS_ReportError(cx, "Argument must be a function");
return false;
}
gInterruptFunc = value;
GetShellRuntime(cx)->interruptFunc = value;
args.rval().setUndefined();
return true;
@ -2940,10 +3007,11 @@ SetInterruptCallback(JSContext* cx, unsigned argc, Value* vp)
static bool
EnableLastWarning(JSContext* cx, unsigned argc, Value* vp)
{
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp);
gLastWarningEnabled = true;
gLastWarning.setNull();
sr->lastWarningEnabled = true;
sr->lastWarning.setNull();
args.rval().setUndefined();
return true;
@ -2952,10 +3020,11 @@ EnableLastWarning(JSContext* cx, unsigned argc, Value* vp)
static bool
DisableLastWarning(JSContext* cx, unsigned argc, Value* vp)
{
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp);
gLastWarningEnabled = false;
gLastWarning.setNull();
sr->lastWarningEnabled = false;
sr->lastWarning.setNull();
args.rval().setUndefined();
return true;
@ -2964,31 +3033,33 @@ DisableLastWarning(JSContext* cx, unsigned argc, Value* vp)
static bool
GetLastWarning(JSContext* cx, unsigned argc, Value* vp)
{
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp);
if (!gLastWarningEnabled) {
if (!sr->lastWarningEnabled) {
JS_ReportError(cx, "Call enableLastWarning first.");
return false;
}
if (!JS_WrapValue(cx, &gLastWarning))
if (!JS_WrapValue(cx, &sr->lastWarning))
return false;
args.rval().set(gLastWarning);
args.rval().set(sr->lastWarning);
return true;
}
static bool
ClearLastWarning(JSContext* cx, unsigned argc, Value* vp)
{
ShellRuntime* sr = GetShellRuntime(cx);
CallArgs args = CallArgsFromVp(argc, vp);
if (!gLastWarningEnabled) {
if (!sr->lastWarningEnabled) {
JS_ReportError(cx, "Call enableLastWarning first.");
return false;
}
gLastWarning.setNull();
sr->lastWarning.setNull();
args.rval().setUndefined();
return true;
@ -3893,6 +3964,11 @@ static bool
SetCachingEnabled(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (GetShellRuntime(cx)->isWorker) {
JS_ReportError(cx, "Caching is not supported in workers");
return false;
}
jsCachingEnabled = ToBoolean(args.get(0));
args.rval().setUndefined();
return true;
@ -5142,7 +5218,7 @@ CreateLastWarningObject(JSContext* cx, JSErrorReport* report)
if (!DefineProperty(cx, warningObj, cx->names().columnNumber, columnVal))
return false;
gLastWarning.setObject(*warningObj);
GetShellRuntime(cx)->lastWarning.setObject(*warningObj);
return true;
}
@ -5184,7 +5260,9 @@ PrintStackTrace(JSContext* cx, HandleValue exn)
void
js::shell::my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
{
if (report && JSREPORT_IS_WARNING(report->flags) && gLastWarningEnabled) {
ShellRuntime* sr = GetShellRuntime(cx);
if (report && JSREPORT_IS_WARNING(report->flags) && sr->lastWarningEnabled) {
JS::AutoSaveExceptionState savedExc(cx);
if (!CreateLastWarningObject(cx, report)) {
fputs("Unhandled error happened while creating last warning object.\n", gOutFile);
@ -5198,7 +5276,7 @@ js::shell::my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* r
if (JS_IsExceptionPending(cx))
(void) JS_GetPendingException(cx, &exn);
gGotError = PrintError(cx, gErrFile, message, report, reportWarnings);
sr->gotError = PrintError(cx, gErrFile, message, report, reportWarnings);
if (!exn.isUndefined()) {
JS::AutoSaveExceptionState savedExc(cx);
if (!PrintStackTrace(cx, exn))
@ -5207,11 +5285,10 @@ js::shell::my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* r
}
if (report->exnType != JSEXN_NONE && !JSREPORT_IS_WARNING(report->flags)) {
if (report->errorNumber == JSMSG_OUT_OF_MEMORY) {
gExitCode = EXITCODE_OUT_OF_MEMORY;
} else {
gExitCode = EXITCODE_RUNTIME_ERROR;
}
if (report->errorNumber == JSMSG_OUT_OF_MEMORY)
sr->exitCode = EXITCODE_OUT_OF_MEMORY;
else
sr->exitCode = EXITCODE_RUNTIME_ERROR;
}
}
@ -5222,7 +5299,7 @@ my_OOMCallback(JSContext* cx, void* data)
// memory", which may or may not be caught. Otherwise the engine will just
// unwind and return null/false, with no exception set.
if (!JS_IsRunning(cx))
gGotError = true;
GetShellRuntime(cx)->gotError = true;
}
static bool
@ -5767,6 +5844,13 @@ NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
return nullptr;
#endif
bool succeeded;
if (!JS_SetImmutablePrototype(cx, glob, &succeeded))
return nullptr;
MOZ_ASSERT(succeeded,
"a fresh, unexposed global object is always capable of "
"having its [[Prototype]] be immutable");
#ifdef JS_HAS_CTYPES
if (!JS_InitCTypesClass(cx, glob))
return nullptr;
@ -5880,6 +5964,8 @@ OptionFailure(const char* option, const char* str)
static int
ProcessArgs(JSContext* cx, OptionParser* op)
{
ShellRuntime* sr = GetShellRuntime(cx);
if (op->getBoolOption('s'))
JS::RuntimeOptionsRef(cx).toggleExtraWarnings();
@ -5892,7 +5978,7 @@ ProcessArgs(JSContext* cx, OptionParser* op)
if (filePaths.empty() && codeChunks.empty() && !op->getStringArg("script")) {
Process(cx, nullptr, true); /* Interactive. */
return gExitCode;
return sr->exitCode;
}
while (!filePaths.empty() || !codeChunks.empty()) {
@ -5901,8 +5987,8 @@ ProcessArgs(JSContext* cx, OptionParser* op)
if (fpArgno < ccArgno) {
char* path = filePaths.front();
Process(cx, path, false);
if (gExitCode)
return gExitCode;
if (sr->exitCode)
return sr->exitCode;
filePaths.popFront();
} else {
const char* code = codeChunks.front();
@ -5910,27 +5996,27 @@ ProcessArgs(JSContext* cx, OptionParser* op)
JS::CompileOptions opts(cx);
opts.setFileAndLine("-e", 1);
if (!JS::Evaluate(cx, opts, code, strlen(code), &rval))
return gExitCode ? gExitCode : EXITCODE_RUNTIME_ERROR;
return sr->exitCode ? sr->exitCode : EXITCODE_RUNTIME_ERROR;
codeChunks.popFront();
if (gQuitting)
if (sr->quitting)
break;
}
}
if (gQuitting)
return gExitCode ? gExitCode : EXIT_SUCCESS;
if (sr->quitting)
return sr->exitCode ? sr->exitCode : EXIT_SUCCESS;
/* The |script| argument is processed after all options. */
if (const char* path = op->getStringArg("script")) {
Process(cx, path, false);
if (gExitCode)
return gExitCode;
if (sr->exitCode)
return sr->exitCode;
}
if (op->getBoolOption('i'))
Process(cx, nullptr, true);
return gExitCode ? gExitCode : EXIT_SUCCESS;
return sr->exitCode ? sr->exitCode : EXIT_SUCCESS;
}
static bool
@ -6530,13 +6616,18 @@ main(int argc, char** argv, char** envp)
if (!rt)
return 1;
mozilla::UniquePtr<ShellRuntime> sr = MakeUnique<ShellRuntime>();
if (!sr)
return 1;
JS_SetRuntimePrivate(rt, sr.get());
JS_SetErrorReporter(rt, my_ErrorReporter);
JS::SetOutOfMemoryCallback(rt, my_OOMCallback, nullptr);
if (!SetRuntimeOptions(rt, op))
return 1;
gInterruptFunc.init(rt, NullValue());
gLastWarning.init(rt, NullValue());
sr->interruptFunc.init(rt, NullValue());
sr->lastWarning.init(rt, NullValue());
JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff);
@ -6594,7 +6685,7 @@ main(int argc, char** argv, char** envp)
DestroyContext(cx, true);
KillWatchdog();
KillWatchdog(rt);
MOZ_ASSERT_IF(!CanUseExtraThreads(), workerThreads.empty());
for (size_t i = 0; i < workerThreads.length(); i++)

View File

@ -36,11 +36,11 @@ class base {
override() { overrideCalled = "base" }
}
class derived extends base {
constructor() { };
constructor() { super(); };
override() { overrideCalled = "derived"; }
}
var derivedExpr = class extends base {
constructor() { };
constructor() { super(); };
override() { overrideCalled = "derived"; }
};

View File

@ -18,6 +18,7 @@ class derived extends base {
// Make sure eval and arrows are still valid in non-derived constructors.
new base();
// Eval throws in derived class constructors, in both class expressions and
// statements.
assertThrowsInstanceOf((() => new derived()), InternalError);
@ -26,8 +27,8 @@ assertThrowsInstanceOf((() => new class extends base { constructor() { eval('')
var g = newGlobal();
var dbg = Debugger(g);
dbg.onDebuggerStatement = function(frame) { assertThrowsInstanceOf(()=>frame.eval(''), InternalError); };
g.eval("new class foo extends null { constructor() { debugger; } }()");
g.eval("new class foo extends null { constructor() { debugger; return {}; } }()");
`;
if (classesEnabled())

View File

@ -0,0 +1,19 @@
// Since we (for now!) can't emit jitcode for derived class statements. Make
// sure we can corectly invoke derived class constructors.
class foo extends null {
constructor() {
// Anything that tests |this| should throw, so just let it run off the
// end.
}
}
function intermediate() {
new foo();
}
for (let i = 0; i < 1100; i++)
assertThrownErrorContains(intermediate, "|this|");
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,15 @@
class foo extends null {
constructor() {
// Returning a primitive is a TypeError in derived constructors. This
// ensures that super() can take the return value directly, without
// checking it. Use |null| here, as a tricky check to make sure we
// didn't lump it in with the object check, somehow.
return null;
}
}
for (let i = 0; i < 1100; i++)
assertThrownErrorContains(() => new foo(), "return");
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,18 @@
function pleaseRunMyCode() { }
class foo extends null {
constructor() {
// Just bareword |this| is DCEd by the BytecodeEmitter. Your guess as
// to why we think this is a good idea is as good as mine. In order to
// combat this inanity, make it a function arg, so we have to compute
// it.
pleaseRunMyCode(this);
assertEq(false, true);
}
}
for (let i = 0; i < 1100; i++)
assertThrownErrorContains(() => new foo(), "|this|");
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,11 @@
class foo extends null {
constructor() {
// Let it fall off the edge and throw.
}
}
for (let i = 0; i < 1100; i++)
assertThrownErrorContains(() => new foo(), "|this|");
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,13 @@
class foo extends null {
constructor() {
// If you return an object, we don't care that |this| went
// uninitialized
return {};
}
}
for (let i = 0; i < 1100; i++)
new foo();
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,13 @@
class foo extends null {
constructor() {
// Explicit returns of undefined should act the same as falling off the
// end of the function. That is to say, they should throw.
return undefined;
}
}
for (let i = 0; i < 1100; i++)
assertThrownErrorContains(() => new foo(), "|this|");
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,17 @@
var test = `
class base { constructor() { } }
class inst extends base { constructor() { super(); } }
Object.setPrototypeOf(inst, Math.sin);
assertThrowsInstanceOf(() => new inst(), TypeError);
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,30 @@
var test = `
class base { constructor() { } }
// lies and the lying liars who tell them
function lies() { }
lies.prototype = 4;
assertThrowsInstanceOf(()=>Reflect.consruct(base, [], lies), TypeError);
// lie a slightly different way
function get(target, property, receiver) {
if (property === "prototype")
return 42;
return Reflect.get(target, property, receiver);
}
class inst extends base {
constructor() { super(); }
}
assertThrowsInstanceOf(()=>new new Proxy(inst, {get})(), TypeError);
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,53 @@
var test = `
function testBase(base) {
class instance extends base {
constructor(inst, one) {
super(inst, one);
}
}
let inst = new instance(instance, 1);
assertEq(Object.getPrototypeOf(inst), instance.prototype);
assertEq(inst.calledBase, true);
}
class base {
// Base class must be [[Construct]]ed, as you cannot [[Call]] a class
// constructor
constructor(nt, one) {
assertEq(new.target, nt);
// Check argument ordering
assertEq(one, 1);
this.calledBase = true;
}
}
testBase(base);
testBase(class extends base {
constructor(nt, one) {
// Every step of the way, new.target and args should be right
assertEq(new.target, nt);
assertEq(one, 1);
super(nt, one);
}
});
function baseFunc(nt, one) {
assertEq(new.target, nt);
assertEq(one, 1);
this.calledBase = true;
}
testBase(baseFunc);
testBase(new Proxy(baseFunc, {}));
// Object will have to wait for fixed builtins.
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,7 @@
// super() invalid outside derived class constructors, including in dynamic
// functions and eval
assertThrowsInstanceOf(() => new Function("super();"), SyntaxError);
assertThrowsInstanceOf(() => eval("super()"), SyntaxError);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,15 @@
var test = `
class instance extends null {
constructor() { super(); }
}
assertThrowsInstanceOf(() => new instance(), TypeError);
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,33 @@
var test = `
function base() { }
class beforeSwizzle extends base {
constructor() {
super(Object.setPrototypeOf(beforeSwizzle, null));
}
}
new beforeSwizzle();
// Again, testing both dynamic prototype dispatch, and that we get the function
// before evaluating args
class beforeThrow extends base {
constructor() {
function thrower() { throw new Error(); }
super(thrower());
}
}
Object.setPrototypeOf(beforeThrow, Math.sin);
// Will throw that Math.sin is not a constructor before evaluating the args
assertThrowsInstanceOf(() => new beforeThrow(), TypeError);
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,33 @@
var test = `
class base1 {
constructor() {
this.base = 1;
}
}
class base2 {
constructor() {
this.base = 2;
}
}
class inst extends base1 {
constructor() {
super();
}
}
assertEq(new inst().base, 1);
Object.setPrototypeOf(inst, base2);
assertEq(new inst().base, 2);
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,34 @@
var test = `
class base {
constructor(a, b, c) {
assertEq(a, 1);
assertEq(b, 2);
assertEq(c, 3);
this.calledBase = true;
}
}
class test extends base {
constructor(arr) {
super(...arr);
}
}
assertEq(new test([1,2,3]).calledBase, true);
class testRest extends base {
constructor(...args) {
super(...args);
}
}
assertEq(new testRest(1,2,3).calledBase, true);
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -0,0 +1,52 @@
var test = `
function base() { this.prop = 42; }
class testInitialize extends base {
constructor() {
// A poor man's assertThrowsInstanceOf, as arrow functions are currently
// disabled in this context
try {
this;
throw new Error();
} catch (e if e instanceof ReferenceError) { }
super();
assertEq(this.prop, 42);
}
}
assertEq(new testInitialize().prop, 42);
// super() twice is a no-go.
class willThrow extends base {
constructor() {
super();
super();
}
}
assertThrowsInstanceOf(()=>new willThrow(), ReferenceError);
// This is determined at runtime, not the syntax level.
class willStillThrow extends base {
constructor() {
for (let i = 0; i < 3; i++) {
super();
}
}
}
assertThrowsInstanceOf(()=>new willStillThrow(), ReferenceError);
class canCatchThrow extends base {
constructor() {
super();
try { super(); } catch(e) { }
}
}
assertEq(new canCatchThrow().prop, 42);
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -13,7 +13,7 @@ class base {
}
class derived extends base {
constructor() {}
constructor() { super(); }
get a() { return super.getValue(); }
set a(v) { super.setValue(v); }

View File

@ -4,12 +4,13 @@ class Base {
constructor() {}
}
class Mid extends Base {
constructor() {}
constructor() { super(); }
f() { return new super.constructor(); }
}
class Derived extends Mid {
constructor() {}
constructor() { super(); }
}
let d = new Derived();
var df = d.f();
assertEq(df.constructor, Base);

View File

@ -9,7 +9,7 @@ class base {
}
class middle extends base {
constructor() { }
constructor() { super(); }
testChain() {
this.middleCalled = true;
super.testChain();
@ -17,7 +17,7 @@ class middle extends base {
}
class derived extends middle {
constructor() { }
constructor() { super(); }
testChain() {
super.testChain();
assertEq(this.middleCalled, true);
@ -32,7 +32,7 @@ function bootlegMiddle() { }
bootlegMiddle.prototype = middle.prototype;
new class extends bootlegMiddle {
constructor() { }
constructor() { super(); }
testChain() {
super.testChain();
assertEq(this.middleCalled, true);
@ -43,11 +43,11 @@ new class extends bootlegMiddle {
// Now let's try out some "long" chains
base.prototype.x = "yeehaw";
let chain = class extends base { constructor() { } }
let chain = class extends base { constructor() { super(); } }
const CHAIN_LENGTH = 100;
for (let i = 0; i < CHAIN_LENGTH; i++)
chain = class extends chain { constructor() { } }
chain = class extends chain { constructor() { super(); } }
// Now we poke the chain
let inst = new chain();

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