Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-01-26 16:28:17 -05:00
commit 9aa5f90ca7
126 changed files with 2450 additions and 943 deletions

View File

@ -525,11 +525,8 @@ Accessible::ChildAtPoint(int32_t aX, int32_t aY,
{
// If we can't find the point in a child, we will return the fallback answer:
// we return |this| if the point is within it, otherwise nullptr.
nsIntRect rect = Bounds();
if (rect.IsEmpty())
return nullptr;
Accessible* fallbackAnswer = nullptr;
nsIntRect rect = Bounds();
if (aX >= rect.x && aX < rect.x + rect.width &&
aY >= rect.y && aY < rect.y + rect.height)
fallbackAnswer = this;

View File

@ -68,6 +68,8 @@ if (!MAC) {
hitTest("imgmap", theLetterA, theLetterA);
hitTest("container", "imgmap", theLetterA);
// hit testing for element contained by zero-width element
hitTest("container2", "container2_input", "container2_input");
SimpleTest.finish();
}
@ -106,5 +108,8 @@ if (!MAC) {
<img id="imgmap" width="447" height="15" usemap="#atoz_map" src="../letters.gif"/>
</div>
<div id="container2" style="width: 0px">
<input id="container2_input">
</div>
</body>
</html>

View File

@ -1186,7 +1186,7 @@ pref("security.sandbox.windows.log", false);
// To get a different setting for a particular plugin replace "default", with
// the plugin's nice file name, see: nsPluginTag::GetNiceFileName.
pref("dom.ipc.plugins.sandbox.default", false);
pref("dom.ipc.plugins.sandbox.flash", false);
pref("dom.ipc.plugins.sandbox.flash", true);
#if defined(MOZ_CONTENT_SANDBOX)
// This controls whether the Windows content process sandbox is using a more

View File

@ -3383,10 +3383,8 @@ nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
{
SetIsActive(value);
}
if (NS_SUCCEEDED(parentAsDocShell->GetIsPrerendered(&value))) {
if (value) {
SetIsPrerendered(true);
}
if (parentAsDocShell->GetIsPrerendered()) {
SetIsPrerendered(true);
}
if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
value = false;

View File

@ -624,7 +624,7 @@ interface nsIDocShell : nsIDocShellTreeItem
* native code to be able to put a docshell in prerendering.
*/
[noscript] void SetIsPrerendered(in boolean prerendered);
readonly attribute boolean isPrerendered;
[infallible] readonly attribute boolean isPrerendered;
/**
* The ID of the docshell in the session history.

View File

@ -397,10 +397,10 @@ EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
lm->~EventListenerManagerMapEntry();
}
class SameOriginChecker MOZ_FINAL : public nsIChannelEventSink,
public nsIInterfaceRequestor
class SameOriginCheckerImpl MOZ_FINAL : public nsIChannelEventSink,
public nsIInterfaceRequestor
{
~SameOriginChecker() {}
~SameOriginCheckerImpl() {}
NS_DECL_ISUPPORTS
NS_DECL_NSICHANNELEVENTSINK
@ -5648,11 +5648,11 @@ nsContentUtils::StringContainsASCIIUpper(const nsAString& aStr)
/* static */
nsIInterfaceRequestor*
nsContentUtils::GetSameOriginChecker()
nsContentUtils::SameOriginChecker()
{
if (!sSameOriginChecker) {
sSameOriginChecker = new SameOriginChecker();
NS_IF_ADDREF(sSameOriginChecker);
sSameOriginChecker = new SameOriginCheckerImpl();
NS_ADDREF(sSameOriginChecker);
}
return sSameOriginChecker;
}
@ -5683,15 +5683,15 @@ nsContentUtils::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel
return rv;
}
NS_IMPL_ISUPPORTS(SameOriginChecker,
NS_IMPL_ISUPPORTS(SameOriginCheckerImpl,
nsIChannelEventSink,
nsIInterfaceRequestor)
NS_IMETHODIMP
SameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
uint32_t aFlags,
nsIAsyncVerifyRedirectCallback *cb)
SameOriginCheckerImpl::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
nsIChannel* aNewChannel,
uint32_t aFlags,
nsIAsyncVerifyRedirectCallback* cb)
{
NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
@ -5704,7 +5704,7 @@ SameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
}
NS_IMETHODIMP
SameOriginChecker::GetInterface(const nsIID & aIID, void **aResult)
SameOriginCheckerImpl::GetInterface(const nsIID& aIID, void** aResult)
{
return QueryInterface(aIID, aResult);
}

View File

@ -1635,7 +1635,7 @@ public:
// Returns NS_OK for same origin, error (NS_ERROR_DOM_BAD_URI) if not.
static nsresult CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel);
static nsIInterfaceRequestor* GetSameOriginChecker();
static nsIInterfaceRequestor* SameOriginChecker();
/**
* Get the Origin of the passed in nsIPrincipal or nsIURI. If the passed in

View File

@ -1337,8 +1337,7 @@ nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
nsIDocument* doc = aRequestingNode->OwnerDoc();
nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::GetSameOriginChecker();
NS_ENSURE_TRUE(req, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::SameOriginChecker();
nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
nsCOMPtr<nsIChannel> channel;

View File

@ -4342,10 +4342,11 @@ nsGlobalWindow::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
}
/* static */ bool
nsGlobalWindow::IsChromeWindow(JSContext* aCx, JSObject* aObj)
nsGlobalWindow::IsPrivilegedChromeWindow(JSContext* aCx, JSObject* aObj)
{
// For now, have to deal with XPConnect objects here.
return xpc::WindowOrNull(aObj)->IsChromeWindow();
return xpc::WindowOrNull(aObj)->IsChromeWindow() &&
nsContentUtils::ObjectPrincipal(aObj) == nsContentUtils::GetSystemPrincipal();
}
/* static */ bool

View File

@ -491,7 +491,7 @@ public:
void GetSupportedNames(nsTArray<nsString>& aNames);
static bool IsChromeWindow(JSContext* /* unused */, JSObject* aObj);
static bool IsPrivilegedChromeWindow(JSContext* /* unused */, JSObject* aObj);
static bool IsShowModalDialogEnabled(JSContext* /* unused */ = nullptr,
JSObject* /* unused */ = nullptr);

View File

@ -20,6 +20,7 @@
#include "jsfriendapi.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "nsIDocShell.h"
#include "nsIDOMGlobalPropertyInitializer.h"
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
@ -2381,12 +2382,47 @@ CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[
return false;
}
bool
CheckSafetyInPrerendering(JSContext* aCx, JSObject* aObj)
void
HandlePrerenderingViolation(nsPIDOMWindow* aWindow)
{
//TODO: Check if page is being prerendered.
//Returning false for now.
return false;
// Suspend the window and its workers, and its children too.
aWindow->SuspendTimeouts();
// Suspend event handling on the document
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
if (doc) {
doc->SuppressEventHandling(nsIDocument::eEvents);
}
}
bool
EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj)
{
JS::Rooted<JSObject*> thisObj(aCx, js::CheckedUnwrap(aObj));
if (!thisObj) {
// Without a this object, we cannot check the safety.
return true;
}
nsGlobalWindow* window = xpc::WindowGlobalOrNull(thisObj);
if (!window) {
// Without a window, we cannot check the safety.
return true;
}
nsIDocShell* docShell = window->GetDocShell();
if (!docShell) {
// Without a docshell, we cannot check the safety.
return true;
}
if (docShell->GetIsPrerendered()) {
HandlePrerenderingViolation(window);
// When the bindings layer sees a false return value, it returns false form
// the JSNative in order to trigger an uncatchable exception.
return false;
}
return true;
}
bool

View File

@ -3142,9 +3142,20 @@ AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
bool
CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
//Returns true if page is being prerendered.
// This function is called by the bindings layer for methods/getters/setters
// that are not safe to be called in prerendering mode. It checks to make sure
// that the |this| object is not running in a global that is in prerendering
// mode. Otherwise, it aborts execution of timers and event handlers, and
// returns false which gets converted to an uncatchable exception by the
// bindings layer.
bool
CheckSafetyInPrerendering(JSContext* aCx, JSObject* aObj);
EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj);
// Handles the violation of a blacklisted action in prerendering mode by
// aborting the scripts, and preventing timers and event handlers from running
// in the window in the future.
void
HandlePrerenderingViolation(nsPIDOMWindow* aWindow);
bool
CallerSubsumes(JSObject* aObject);

View File

@ -1829,7 +1829,7 @@ addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSou
addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
addExternalIface('MozSmsMessage')
addExternalIface('MozTreeView', nativeType='nsITreeView',
headerFile='nsITreeView.h')
headerFile='nsITreeView.h', notflattened=True)
addExternalIface('MozWakeLockListener', headerFile='nsIDOMWakeLockListener.h')
addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
addExternalIface('nsIBrowserDOMWindow', nativeType='nsIBrowserDOMWindow',

View File

@ -6506,8 +6506,10 @@ class CGPerSignatureCall(CGThing):
for i in descriptor.interface.getInheritedInterfaces())):
cgThings.append(CGGeneric(dedent(
"""
if (mozilla::dom::CheckSafetyInPrerendering(cx, obj)) {
//TODO: Handle call into unsafe API during Prerendering (Bug 730101)
if (!mozilla::dom::EnforceNotInPrerendering(cx, obj)) {
// Return false from the JSNative in order to trigger
// an uncatchable exception.
MOZ_ASSERT(!JS_IsExceptionPending(cx));
return false;
}
""")))

View File

@ -6,3 +6,8 @@
[test_dom_xrays.html]
[test_proxies_via_xray.html]
[test_document_location_via_xray_cached.html]
[test_blacklisted_prerendering_function.xul]
support-files =
file_focuser.html
file_fullScreenPropertyAccessor.html
skip-if = e10s # prerendering doesn't work in e10s yet

View File

@ -0,0 +1,24 @@
<!DOCTYPE HTML>
<div id="stage"></div>
<script>
function stage(str) {
var s = document.getElementById("stage");
s.textContent = str;
}
stage("before");
setTimeout(function() {
stage("in timeout");
});
setInterval(function() {
stage("in interval");
});
addEventListener("keydown", function() {
stage("keydown");
}, false);
try {
focus();
stage("after");
} catch(e) {
stage("exception raised");
}
</script>

View File

@ -0,0 +1,24 @@
<!DOCTYPE HTML>
<div id="stage"></div>
<script>
function stage(str) {
var s = document.getElementById("stage");
s.textContent = str;
}
stage("before");
setTimeout(function() {
stage("in timeout");
});
setInterval(function() {
stage("in interval");
});
addEventListener("keydown", function() {
stage("keydown");
}, false);
try {
window.fullScreen;
stage("after");
} catch(e) {
stage("exception raised");
}
</script>

View File

@ -0,0 +1,124 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
onload="runTest();">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script class="testbody" type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
function Listener(aBrowser, aPrerendered, aCallback) {
this.init(aBrowser, aPrerendered, aCallback);
}
Listener.prototype = {
init: function(aBrowser, aPrerendered, aCallback) {
this.mBrowser = aBrowser;
this.mPrerendered = aPrerendered;
this.mCallback = aCallback;
},
QueryInterface: function(aIID) {
if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
aIID.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_NOINTERFACE;
},
onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus) {
if ((aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP) &&
(aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_IS_DOCUMENT)) {
var doc = this.mBrowser.contentDocument;
var stage = doc.getElementById("stage");
if (this.mPrerendered) {
is(stage.textContent, "before", "The blacklisted call should properly be intercepted in prerendering mode");
} else {
// In normal mode, we may or may not have run the timeout and/or the interval.
switch (stage.textContent) {
case "after":
case "in timeout":
case "in interval":
ok(true, "The blacklisted call should work fine in normal mode");
break;
default:
ok(false, "The blacklisted call should work fine in normal mode");
break;
}
}
progress.removeProgressListener(progressListener);
// Set three timeouts to see if the interval triggered
var self = this;
function checkInterval() {
var expected = self.mPrerendered ? "before" : "in interval";
var desc = self.mPrerendered ? "No timer should be running" : "Timers should run as normal";
is(stage.textContent, expected, desc);
// Now, dispatch a key event to the window and see if the keydown handler runs
synthesizeKey("a", {}, self.mBrowser.contentWindow);
expected = self.mPrerendered ? "before" : "keydown";
desc = self.mPrerendered ? "No event handler should be running" : "Event handlers should run as normal";
is(stage.textContent, expected, desc);
self.mCallback();
}
setTimeout(function() {
setTimeout(function() {
setTimeout(function() {
checkInterval();
}, 0);
}, 0);
}, 0);
}
},
onProgressChange : function(aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {},
onLocationChange : function(aWebProgress, aRequest, aLocation, aFlags) {},
onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage) {},
onSecurityChange : function(aWebProgress, aRequest, aState) {},
mBrowser: null,
mPrerendered: false,
mCallback: null
};
var progress, progressListener;
function runTest() {
testStep(false, "file_focuser.html", function() {
testStep(true, "file_focuser.html", function() {
testStep(false, "file_fullScreenPropertyAccessor.html", function() {
testStep(true, "file_fullScreenPropertyAccessor.html", function() {
SimpleTest.finish();
});
});
});
});
}
function testStep(aPrerendered, aFileName, aCallback) {
var browser = document.getElementById(aPrerendered ? "prerendered" : "normal");;
progressListener = new Listener(browser, aPrerendered, aCallback);
var docShell = browser.docShell;
progress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebProgress);
progress.addProgressListener(progressListener,
Components.interfaces.nsIWebProgress.NOTIFY_ALL);
browser.loadURI("chrome://mochitests/content/chrome/dom/bindings/test/" + aFileName);
}
]]>
</script>
<body id="html_body" xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069719">Mozilla Bug 1069719</a>
<p id="display"></p>
<pre id="test">
</pre>
</body>
<browser prerendered="true" id="prerendered"/>
<browser id="normal"/>
</window>

View File

@ -14,6 +14,7 @@
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
#include "mozilla/sandboxTarget.h"
#include "mozilla/Scoped.h"
#include "windows.h"
#include <intrin.h>
#include <assert.h>
@ -33,6 +34,31 @@
#include "sha256.h"
#endif
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
namespace {
// Scoped type used by Load
struct ScopedActCtxHandleTraits
{
typedef HANDLE type;
static type empty()
{
return INVALID_HANDLE_VALUE;
}
static void release(type aActCtxHandle)
{
if (aActCtxHandle != INVALID_HANDLE_VALUE) {
ReleaseActCtx(aActCtxHandle);
}
}
};
typedef mozilla::Scoped<ScopedActCtxHandleTraits> ScopedActCtxHandle;
} // anonymous namespace
#endif
namespace mozilla {
namespace gmp {
@ -168,6 +194,30 @@ GMPLoaderImpl::Load(const char* aLibPath,
nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen);
}
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
// If the GMP DLL is a side-by-side assembly with static imports then the DLL
// loader will attempt to create an activation context which will fail because
// of the sandbox. If we create an activation context before we start the
// sandbox then this one will get picked up by the DLL loader.
int pathLen = MultiByteToWideChar(CP_ACP, 0, aLibPath, -1, nullptr, 0);
if (pathLen == 0) {
return false;
}
wchar_t* widePath = new wchar_t[pathLen];
if (MultiByteToWideChar(CP_ACP, 0, aLibPath, -1, widePath, pathLen) == 0) {
delete[] widePath;
return false;
}
ACTCTX actCtx = { sizeof(actCtx) };
actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
actCtx.lpSource = widePath;
actCtx.lpResourceName = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
ScopedActCtxHandle actCtxHandle(CreateActCtx(&actCtx));
delete[] widePath;
#endif
// Start the sandbox now that we've generated the device bound node id.
// This must happen after the node id is bound to the device id, as
// generating the device id requires privileges.

View File

@ -19,6 +19,7 @@
#include "nsIRunnable.h"
#include "nsThreadUtils.h"
#include "prlog.h"
#include <time.h>
struct JSContext;
class JSObject;
@ -36,14 +37,37 @@ extern PRLogModuleInfo* GetMediaSourceAPILog();
#define MSE_API(...)
#endif
// RangeRemoval must be synchronous if appendBuffer is also synchronous.
// While waiting for bug 1118589 to land, ensure RangeRemoval is synchronous
#define APPENDBUFFER_IS_SYNCHRONOUS
namespace mozilla {
namespace dom {
class AppendDataRunnable : public nsRunnable {
public:
AppendDataRunnable(SourceBuffer* aSourceBuffer,
const uint8_t* aData,
uint32_t aLength,
double aTimestampOffset)
: mSourceBuffer(aSourceBuffer)
, mTimestampOffset(aTimestampOffset)
{
mData.AppendElements(aData, aLength);
}
NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
mSourceBuffer->AppendData(mData.Elements(),
mData.Length(),
mTimestampOffset);
return NS_OK;
}
private:
nsRefPtr<SourceBuffer> mSourceBuffer;
nsTArray<uint8_t> mData;
double mTimestampOffset;
};
class RangeRemovalRunnable : public nsRunnable {
public:
RangeRemovalRunnable(SourceBuffer* aSourceBuffer,
@ -240,18 +264,8 @@ SourceBuffer::RangeRemoval(double aStart, double aEnd)
{
StartUpdating();
#if defined(APPENDBUFFER_IS_SYNCHRONOUS)
DoRangeRemoval(aStart, aEnd);
// Run the final step of the buffer append algorithm asynchronously to
// ensure the SourceBuffer's updating flag transition behaves as required
// by the spec.
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
NS_DispatchToMainThread(event);
#else
nsRefPtr<nsIRunnable> task = new RangeRemovalRunnable(this, aStart, aEnd);
NS_DispatchToMainThread(task);
#endif
}
void
@ -267,9 +281,7 @@ SourceBuffer::DoRangeRemoval(double aStart, double aEnd)
mTrackBuffer->RangeRemoval(start, end);
}
#if !defined(APPENDBUFFER_IS_SYNCHRONOUS)
StopUpdating();
#endif
}
void
@ -405,10 +417,29 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
MOZ_ASSERT(mAppendMode == SourceBufferAppendMode::Segments,
"We don't handle timestampOffset for sequence mode yet");
nsRefPtr<nsIRunnable> task =
new AppendDataRunnable(this, aData, aLength, mTimestampOffset);
NS_DispatchToMainThread(task);
}
void
SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, double aTimestampOffset)
{
if (!mUpdating) {
// The buffer append algorithm has been interrupted by abort().
//
// If the sequence appendBuffer(), abort(), appendBuffer() occurs before
// the first StopUpdating() runnable runs, then a second StopUpdating()
// runnable will be scheduled, but still only one (the first) will queue
// events.
return;
}
MOZ_ASSERT(mMediaSource);
if (aLength) {
if (!mTrackBuffer->AppendData(aData, aLength, mTimestampOffset * USECS_PER_S)) {
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethodWithArg<bool>(this, &SourceBuffer::AppendError, true);
NS_DispatchToMainThread(event);
if (!mTrackBuffer->AppendData(aData, aLength, aTimestampOffset * USECS_PER_S)) {
AppendError(true);
return;
}
@ -419,12 +450,8 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
CheckEndTime();
}
// Run the final step of the buffer append algorithm asynchronously to
// ensure the SourceBuffer's updating flag transition behaves as required
// by the spec.
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
NS_DispatchToMainThread(event);
}
StopUpdating();
}
void
SourceBuffer::AppendError(bool aDecoderError)

View File

@ -122,6 +122,7 @@ private:
~SourceBuffer();
friend class AsyncEventRunner<SourceBuffer>;
friend class AppendDataRunnable;
void DispatchSimpleEvent(const char* aName);
void QueueAsyncSimpleEvent(const char* aName);
@ -137,6 +138,8 @@ private:
// Shared implementation of AppendBuffer overloads.
void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
void AppendData(const uint8_t* aData, uint32_t aLength,
double aTimestampOffset);
// Implement the "Append Error Algorithm".
// Will call endOfStream() with "decode" error if aDecodeError is true.

View File

@ -8,6 +8,7 @@
#include "prlog.h"
#include "AbstractMediaDecoder.h"
#include "MediaDecoderReader.h"
#include "mozilla/dom/TimeRanges.h"
#ifdef PR_LOGGING
extern PRLogModuleInfo* GetMediaSourceLog();

View File

@ -405,16 +405,16 @@ partial interface Window {
[Func="IsChromeOrXBL"]
interface ChromeWindow {
[Func="nsGlobalWindow::IsChromeWindow"]
[Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
const unsigned short STATE_MAXIMIZED = 1;
[Func="nsGlobalWindow::IsChromeWindow"]
[Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
const unsigned short STATE_MINIMIZED = 2;
[Func="nsGlobalWindow::IsChromeWindow"]
[Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
const unsigned short STATE_NORMAL = 3;
[Func="nsGlobalWindow::IsChromeWindow"]
[Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
const unsigned short STATE_FULLSCREEN = 4;
[Func="nsGlobalWindow::IsChromeWindow"]
[Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
readonly attribute unsigned short windowState;
/**
@ -422,40 +422,40 @@ interface ChromeWindow {
* utility functions implemented by chrome script. It will be null
* for DOMWindows not corresponding to browsers.
*/
[Throws, Func="nsGlobalWindow::IsChromeWindow"]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
attribute nsIBrowserDOMWindow? browserDOMWindow;
[Throws, Func="nsGlobalWindow::IsChromeWindow"]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
void getAttention();
[Throws, Func="nsGlobalWindow::IsChromeWindow"]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
void getAttentionWithCycleCount(long aCycleCount);
[Throws, Func="nsGlobalWindow::IsChromeWindow"]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
void setCursor(DOMString cursor);
[Throws, Func="nsGlobalWindow::IsChromeWindow", UnsafeInPrerendering]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow", UnsafeInPrerendering]
void maximize();
[Throws, Func="nsGlobalWindow::IsChromeWindow", UnsafeInPrerendering]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow", UnsafeInPrerendering]
void minimize();
[Throws, Func="nsGlobalWindow::IsChromeWindow", UnsafeInPrerendering]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow", UnsafeInPrerendering]
void restore();
/**
* Notify a default button is loaded on a dialog or a wizard.
* defaultButton is the default button.
*/
[Throws, Func="nsGlobalWindow::IsChromeWindow"]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
void notifyDefaultButtonLoaded(Element defaultButton);
[Throws, Func="nsGlobalWindow::IsChromeWindow"]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
readonly attribute nsIMessageBroadcaster messageManager;
/**
* Returns the message manager identified by the given group name that
* manages all frame loaders belonging to that group.
*/
[Throws, Func="nsGlobalWindow::IsChromeWindow"]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
nsIMessageBroadcaster getGroupMessageManager(DOMString aGroup);
/**
@ -468,7 +468,7 @@ interface ChromeWindow {
*
* Throws NS_ERROR_NOT_IMPLEMENTED if the OS doesn't support this.
*/
[Throws, Func="nsGlobalWindow::IsChromeWindow"]
[Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
void beginWindowMove(Event mouseDownEvent, optional Element? panel = null);
};

View File

@ -8,6 +8,7 @@
#define mozilla_dom_ServiceWorkerRegistration_h
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/ServiceWorkerBinding.h"
#include "mozilla/dom/ServiceWorkerCommon.h"
class nsPIDOMWindow;

View File

@ -1100,8 +1100,7 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker = nsContentUtils::GetSameOriginChecker();
NS_ENSURE_TRUE(sameOriginChecker, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker = nsContentUtils::SameOriginChecker();
channel->SetNotificationCallbacks(sameOriginChecker);

View File

@ -434,11 +434,7 @@ XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv)
mListenerManager = elm;
// Create a channel
nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::GetSameOriginChecker();
if (!req) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return false;
}
nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::SameOriginChecker();
nsCOMPtr<nsIChannel> channel;
// nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active,

View File

@ -108,7 +108,7 @@ public:
}
// We're not COM-y, so we don't get refcounts by default
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Decoder)
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Decoder, MOZ_OVERRIDE)
// Implement IResumable.
virtual void Resume() MOZ_OVERRIDE;

View File

@ -453,7 +453,7 @@ AsmJSModule::setAutoFlushICacheRange()
static void
AsmJSReportOverRecursed()
{
JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
JSContext *cx = JSRuntime::innermostAsmJSActivation()->cx();
js_ReportOverRecursed(cx);
}
@ -461,14 +461,14 @@ static void
OnDetached()
{
// See hasDetachedHeap comment in LinkAsmJS.
JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
JSContext *cx = JSRuntime::innermostAsmJSActivation()->cx();
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY);
}
static bool
AsmJSHandleExecutionInterrupt()
{
AsmJSActivation *act = PerThreadData::innermostAsmJSActivation();
AsmJSActivation *act = JSRuntime::innermostAsmJSActivation();
act->module().setInterrupted(true);
bool ret = CheckForInterrupt(act->cx());
act->module().setInterrupted(false);
@ -478,7 +478,7 @@ AsmJSHandleExecutionInterrupt()
static int32_t
CoerceInPlace_ToInt32(MutableHandleValue val)
{
JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
JSContext *cx = JSRuntime::innermostAsmJSActivation()->cx();
int32_t i32;
if (!ToInt32(cx, val, &i32))
@ -491,7 +491,7 @@ CoerceInPlace_ToInt32(MutableHandleValue val)
static int32_t
CoerceInPlace_ToNumber(MutableHandleValue val)
{
JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
JSContext *cx = JSRuntime::innermostAsmJSActivation()->cx();
double dbl;
if (!ToNumber(cx, val, &dbl))
@ -570,7 +570,7 @@ InvokeFromAsmJS(AsmJSActivation *activation, int32_t exitIndex, int32_t argc, Va
static int32_t
InvokeFromAsmJS_Ignore(int32_t exitIndex, int32_t argc, Value *argv)
{
AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
AsmJSActivation *activation = JSRuntime::innermostAsmJSActivation();
JSContext *cx = activation->cx();
RootedValue rval(cx);
@ -582,7 +582,7 @@ InvokeFromAsmJS_Ignore(int32_t exitIndex, int32_t argc, Value *argv)
static int32_t
InvokeFromAsmJS_ToInt32(int32_t exitIndex, int32_t argc, Value *argv)
{
AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
AsmJSActivation *activation = JSRuntime::innermostAsmJSActivation();
JSContext *cx = activation->cx();
RootedValue rval(cx);
@ -602,7 +602,7 @@ InvokeFromAsmJS_ToInt32(int32_t exitIndex, int32_t argc, Value *argv)
static int32_t
InvokeFromAsmJS_ToNumber(int32_t exitIndex, int32_t argc, Value *argv)
{
AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
AsmJSActivation *activation = JSRuntime::innermostAsmJSActivation();
JSContext *cx = activation->cx();
RootedValue rval(cx);

View File

@ -448,7 +448,7 @@ HandleFault(PEXCEPTION_POINTERS exception)
return false;
AutoSetHandlingSignal handling(rt);
AsmJSActivation *activation = rt->mainThread.asmJSActivationStack();
AsmJSActivation *activation = rt->asmJSActivationStack();
if (!activation)
return false;
@ -647,7 +647,7 @@ HandleMachException(JSRuntime *rt, const ExceptionRequest &request)
if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2)
return false;
AsmJSActivation *activation = rt->mainThread.asmJSActivationStack();
AsmJSActivation *activation = rt->asmJSActivationStack();
if (!activation)
return false;
@ -861,7 +861,7 @@ HandleFault(int signum, siginfo_t *info, void *ctx)
return false;
AutoSetHandlingSignal handling(rt);
AsmJSActivation *activation = rt->mainThread.asmJSActivationStack();
AsmJSActivation *activation = rt->asmJSActivationStack();
if (!activation)
return false;
@ -947,12 +947,12 @@ RedirectJitCodeToInterruptCheck(JSRuntime *rt, CONTEXT *context)
{
RedirectIonBackedgesToInterruptCheck(rt);
if (AsmJSActivation *activation = rt->mainThread.asmJSActivationStack()) {
if (AsmJSActivation *activation = rt->asmJSActivationStack()) {
const AsmJSModule &module = activation->module();
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
if (module.containsFunctionPC((void*)rt->mainThread.simulator()->get_pc()))
rt->mainThread.simulator()->set_resume_pc(int32_t(module.interruptExit()));
if (module.containsFunctionPC((void*)rt->simulator()->get_pc()))
rt->simulator()->set_resume_pc(int32_t(module.interruptExit()));
#endif
uint8_t **ppc = ContextToPC(context);

View File

@ -8504,25 +8504,21 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
// The following is inlined:
// JSContext *cx = activation->cx();
// Activation *act = cx->mainThread().activation();
// Activation *act = cx->runtime()->activation();
// act.active_ = true;
// act.prevJitTop_ = cx->mainThread().jitTop;
// act.prevJitJSContext_ = cx->mainThread().jitJSContext;
// cx->mainThread().jitJSContext = cx;
// act.prevJitActivation_ = cx->mainThread().jitActivation;
// cx->mainThread().jitActivation = act;
// act.prevProfilingActivation_ = cx->mainThread().profilingActivation;
// cx->mainThread().profilingActivation_ = act;
// act.prevJitTop_ = cx->runtime()->jitTop;
// act.prevJitJSContext_ = cx->runtime()->jitJSContext;
// cx->runtime()->jitJSContext = cx;
// act.prevJitActivation_ = cx->runtime()->jitActivation;
// cx->runtime()->jitActivation = act;
// act.prevProfilingActivation_ = cx->runtime()->profilingActivation;
// cx->runtime()->profilingActivation_ = act;
// On the ARM store8() uses the secondScratchReg (lr) as a temp.
size_t offsetOfActivation = offsetof(JSRuntime, mainThread) +
PerThreadData::offsetOfActivation();
size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop);
size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
offsetof(PerThreadData, jitJSContext);
size_t offsetOfJitActivation = offsetof(JSRuntime, mainThread) +
offsetof(PerThreadData, jitActivation);
size_t offsetOfProfilingActivation = offsetof(JSRuntime, mainThread) +
PerThreadData::offsetOfProfilingActivation();
size_t offsetOfActivation = JSRuntime::offsetOfActivation();
size_t offsetOfJitTop = offsetof(JSRuntime, jitTop);
size_t offsetOfJitJSContext = offsetof(JSRuntime, jitJSContext);
size_t offsetOfJitActivation = offsetof(JSRuntime, jitActivation);
size_t offsetOfProfilingActivation = JSRuntime::offsetOfProfilingActivation();
masm.loadAsmJSActivation(reg0);
masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg3);
masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0);
@ -8531,26 +8527,26 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
// act.active_ = true;
masm.store8(Imm32(1), Address(reg1, JitActivation::offsetOfActiveUint8()));
// act.prevJitTop_ = cx->mainThread().jitTop;
// act.prevJitTop_ = cx->runtime()->jitTop;
masm.loadPtr(Address(reg0, offsetOfJitTop), reg2);
masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitTop()));
// act.prevJitJSContext_ = cx->mainThread().jitJSContext;
// act.prevJitJSContext_ = cx->runtime()->jitJSContext;
masm.loadPtr(Address(reg0, offsetOfJitJSContext), reg2);
masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitJSContext()));
// cx->mainThread().jitJSContext = cx;
// cx->runtime()->jitJSContext = cx;
masm.storePtr(reg3, Address(reg0, offsetOfJitJSContext));
// act.prevJitActivation_ = cx->mainThread().jitActivation;
// act.prevJitActivation_ = cx->runtime()->jitActivation;
masm.loadPtr(Address(reg0, offsetOfJitActivation), reg2);
masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitActivation()));
// cx->mainThread().jitActivation = act;
// cx->runtime()->jitActivation = act;
masm.storePtr(reg1, Address(reg0, offsetOfJitActivation));
// act.prevProfilingActivation_ = cx->mainThread().profilingActivation;
// act.prevProfilingActivation_ = cx->runtime()->profilingActivation;
masm.loadPtr(Address(reg0, offsetOfProfilingActivation), reg2);
masm.storePtr(reg2, Address(reg1, Activation::offsetOfPrevProfiling()));
// cx->mainThread().profilingActivation_ = act;
// cx->runtime()->profilingActivation_ = act;
masm.storePtr(reg1, Address(reg0, offsetOfProfilingActivation));
}
@ -8571,41 +8567,37 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
Register reg2 = AsmJSIonExitRegD2;
// The following is inlined:
// rt->mainThread.profilingActivation = prevProfilingActivation_;
// rt->mainThread.activation()->active_ = false;
// rt->mainThread.jitTop = prevJitTop_;
// rt->mainThread.jitJSContext = prevJitJSContext_;
// rt->mainThread.jitActivation = prevJitActivation_;
// rt->profilingActivation = prevProfilingActivation_;
// rt->activation()->active_ = false;
// rt->jitTop = prevJitTop_;
// rt->jitJSContext = prevJitJSContext_;
// rt->jitActivation = prevJitActivation_;
// On the ARM store8() uses the secondScratchReg (lr) as a temp.
size_t offsetOfActivation = offsetof(JSRuntime, mainThread) +
PerThreadData::offsetOfActivation();
size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop);
size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
offsetof(PerThreadData, jitJSContext);
size_t offsetOfJitActivation = offsetof(JSRuntime, mainThread) +
offsetof(PerThreadData, jitActivation);
size_t offsetOfProfilingActivation = offsetof(JSRuntime, mainThread) +
PerThreadData::offsetOfProfilingActivation();
size_t offsetOfActivation = JSRuntime::offsetOfActivation();
size_t offsetOfJitTop = offsetof(JSRuntime, jitTop);
size_t offsetOfJitJSContext = offsetof(JSRuntime, jitJSContext);
size_t offsetOfJitActivation = offsetof(JSRuntime, jitActivation);
size_t offsetOfProfilingActivation = JSRuntime::offsetOfProfilingActivation();
masm.movePtr(AsmJSImmPtr(AsmJSImm_Runtime), reg0);
masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
// rt->mainThread.jitTop = prevJitTop_;
// rt->jitTop = prevJitTop_;
masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitTop()), reg2);
masm.storePtr(reg2, Address(reg0, offsetOfJitTop));
// rt->mainThread.profilingActivation = rt->mainThread.activation()->prevProfiling_;
// rt->profilingActivation = rt->activation()->prevProfiling_;
masm.loadPtr(Address(reg1, Activation::offsetOfPrevProfiling()), reg2);
masm.storePtr(reg2, Address(reg0, offsetOfProfilingActivation));
// rt->mainThread.activation()->active_ = false;
// rt->activation()->active_ = false;
masm.store8(Imm32(0), Address(reg1, JitActivation::offsetOfActiveUint8()));
// rt->mainThread.jitJSContext = prevJitJSContext_;
// rt->jitJSContext = prevJitJSContext_;
masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitJSContext()), reg2);
masm.storePtr(reg2, Address(reg0, offsetOfJitJSContext));
// rt->mainThread.jitActivation = prevJitActivation_;
// rt->jitActivation = prevJitActivation_;
masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitActivation()), reg2);
masm.storePtr(reg2, Address(reg0, offsetOfJitActivation));
}

View File

@ -1353,11 +1353,11 @@ js::testingFunc_assertFloat32(JSContext *cx, unsigned argc, jsval *vp)
}
static bool
TestingFunc_assertValidJitStack(JSContext *cx, unsigned argc, jsval *vp)
TestingFunc_assertJitStackInvariants(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
jit::AssertValidJitStack(cx);
jit::AssertJitStackInvariants(cx);
args.rval().setUndefined();
return true;
}
@ -2499,8 +2499,8 @@ gc::ZealModeHelpText),
"bailout()",
" Force a bailout out of ionmonkey (if running in ionmonkey)."),
JS_FN_HELP("assertValidJitStack", TestingFunc_assertValidJitStack, 0, 0,
"assertValidJitStack()",
JS_FN_HELP("assertJitStackInvariants", TestingFunc_assertJitStackInvariants, 0, 0,
"assertJitStackInvariants()",
" Iterates the Jit stack and check that stack invariants hold."),
JS_FN_HELP("setJitCompilerOption", SetJitCompilerOption, 2, 0,

View File

@ -1,39 +1,49 @@
# Spidermonkey JSAPI rooting analysis
This directory contains scripts and a makefile for running Brian Hackett's
static GC rooting analysis on a JS source directory.
To use it:
To use it on SpiderMonkey:
1. Download and compile sixgill. Make sure the gcc plugin is enabled. (The
configure output will tell you.)
1. Be on Fedora/CentOS/RedHat Linux x86_64.
- [sfink] I needed a couple of patches to get it work on Fedora 16/17/18.
Ask me if you need them.
(Specifically, the prebuilt GCC **won't work on Ubuntu**
without the `CFLAGS` and `CXXFLAGS` settings from
http://trac.wildfiregames.com/wiki/StaticRootingAnalysis .)
2. Compile an optimized JS shell that includes the patch at
<http://people.mozilla.org/~sfink/data/bug-835552-cwd-snarf>. This does not
need to be in the same source tree as you are running these scripts from.
Remember the full path to the resulting JS binary; we'll call it $JS_SHELL
below.
2. Have the Gecko build prerequisites installed.
3. |make clean| in the objdir of the JS source tree that you're going to be
analyzing. (These analysis scripts will default to the tree they are within,
but you can point them at another tree.)
3. In this directory, run these commands.
4. in $objdir/js/src/devtools/analysis, |make JS=$JS_SHELL
SIXGILL=.../path/to/sixgill...|. You may need one or more of the following
additional settings in addition to the |JS| already given:
mkdir builddir
cd builddir
../run-analysis.sh
- JSOBJDIR: if you are analyzing a different source tree, set this to the
objdir of the tree you want to analyze.
`run-analysis.sh` is kind of like `configure` and `make` combined:
the build directory can be wherever you want
and you can name it whatever you want.
(You could just run it right here in the source tree, and it would work,
but don't do that -- it spits out files all over the place and
then you'd have to clean up your source tree later.)
- ANALYSIS_SCRIPT_DIR: by default, the *.js files within the directory
containing this README will be used, but you can point to a different
directory full. At the time of this writing, there are some changes not in
bhackett's git repo that are necessary, and you'll also need the
gen-hazards.sh shell script.
Output goes to `hazards.txt` in the builddir.
- JOBS: set this to the number of parallel jobs you'd like to run the final
analysis pass with. This defaults to 6, somewhat randomly, which gave me a
large speedup even on a machine with only 2 cores.
To use this analysis on any other codebase,
make a copy of `run-analysis.sh` and adapt it for your code.
## Overview of what is going on here
So what does `run-analysis.sh` actually do?
1. **It insecurely downloads software over HTTP.** Yeah.
See `run-analysis.sh` for details.
2. It runs `run_complete`, a Perl script, which builds the target
codebase with a custom hacked GCC, generating a few database files
containing (among other data) the full call graph.
3. Then it runs `analyze.py`, a Python script, which runs all the scripts
which actually perform the analysis -- the tricky parts.
(Those scripts are written in JS.)
The results will be in rootingHazards.txt

View File

@ -0,0 +1,85 @@
# setup.sh - Run the rooting analysis on SpiderMonkey. See `README.txt` for usage.
#
# This script is based on the wiki page:
# http://trac.wildfiregames.com/wiki/StaticRootingAnalysis
set -eu
BUILD_DIR="$PWD"
ANALYSIS_SCRIPTDIR="$(dirname $0)"
MOZILLA_SRCDIR="$(cd $ANALYSIS_SCRIPTDIR && (hg root || git rev-parse --show-toplevel))"
# Requirements
# ============
#
# Download and unpack the Sixgill plugin binaries.
# (`wget -c` skips the download if you've already got the file.)
#
# This insecurely downloads software over HTTP. Sorry.
#
# The alternative is building your own Sixgill. That can be a pain and you may
# need some patches to get it to work on your Linux distribution. Ask sfink for
# details.
mkdir -p downloads
(cd downloads && wget -c http://people.mozilla.org/~sfink/data/hazards-sixgill.tar.xz)
tar xf downloads/hazards-sixgill.tar.xz
# Download and unpack GCC binaries compatible with the Sixgill plugin.
(cd downloads && wget -c http://people.mozilla.org/~sfink/data/hazards-gcc4.7.tar.xz)
tar xf downloads/hazards-gcc4.7.tar.xz
# Generate raw data (.xdb files)
# ==============================
#
# The first step is to generate the .xdb files that contain the information
# needed by the analysis. This is done by compiling SpiderMonkey with the
# sixgill plugin enabled. The plugin creates .xdb files which the analysis
# consumes.
PATH=$BUILD_DIR/sixgill/usr/bin:$PATH
export PATH
GCCDIR=$BUILD_DIR/gcc/bin
export GCCDIR
# Create a SpiderMonkey build directory and run configure.
mkdir -p spidermonkey-analysis
(cd spidermonkey-analysis && \
$MOZILLA_SRCDIR/js/src/configure --enable-optimize)
# Make SpiderMonkey.
$MOZILLA_SRCDIR/js/src/devtools/rootAnalysis/run_complete \
--build-root=$BUILD_DIR/spidermonkey-analysis \
--binaries=$BUILD_DIR/sixgill/usr/bin \
--wrap-dir=$BUILD_DIR/sixgill/usr/libexec/sixgill/scripts/wrap_gcc \
--buildcommand='make' \
--foreground \
--no-logs \
.
# Run the analysis
# ================
# Build *another* copy of SpiderMonkey, using the system C++ compiler, without
# Sixgill. This is what we use to run the analysis. (We don't let you skip this
# step by setting a $JS environment variable or something, because you need
# ctypes. Relax and spin a build. Get yourself a cup of tea.)
mkdir -p spidermonkey-opt
(cd spidermonkey-opt && \
$MOZILLA_SRCDIR/js/src/configure --enable-optimize --enable-ctypes --enable-nspr-build && \
make -j8)
JS="$BUILD_DIR/spidermonkey-opt/dist/bin/js"
# Write a config file used by analyze.py.
rm -f defaults.py
echo "objdir = '${BUILD_DIR}/spidermonkey-analysis'" >> defaults.py
echo "sixgill = '${BUILD_DIR}/sixgill/usr/libexec/sixgill'" >> defaults.py
echo "sixgill_bin = '${BUILD_DIR}/sixgill/usr/bin'" >> defaults.py
echo "js = '${JS}'" >> defaults.py
echo "analysis_scriptdir = '${ANALYSIS_SCRIPTDIR}'" >> defaults.py
# Run the script that runs the scripts that do the analysis.
python2.7 "${MOZILLA_SRCDIR}/js/src/devtools/rootAnalysis/analyze.py" -j 8 callgraph

View File

@ -152,7 +152,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx, bool match_only)
// Check if we have space on the stack.
Label stack_ok;
void *stack_limit = runtime->mainThread.addressOfJitStackLimit();
void *stack_limit = runtime->addressOfJitStackLimit();
masm.branchPtr(Assembler::Below, AbsoluteAddress(stack_limit), StackPointer, &stack_ok);
// Exit with an exception. There is not enough space on the stack
@ -262,7 +262,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx, bool match_only)
}
// Initialize backtrack stack pointer.
masm.loadPtr(AbsoluteAddress(runtime->mainThread.regexpStack.addressOfBase()), backtrack_stack_pointer);
masm.loadPtr(AbsoluteAddress(runtime->regexpStack.addressOfBase()), backtrack_stack_pointer);
masm.storePtr(backtrack_stack_pointer, Address(StackPointer, offsetof(FrameData, backtrackStackBase)));
masm.jump(&start_label_);
@ -422,7 +422,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext *cx, bool match_only)
Address backtrackStackBaseAddress(temp2, offsetof(FrameData, backtrackStackBase));
masm.subPtr(backtrackStackBaseAddress, backtrack_stack_pointer);
masm.loadPtr(AbsoluteAddress(runtime->mainThread.regexpStack.addressOfBase()), temp1);
masm.loadPtr(AbsoluteAddress(runtime->regexpStack.addressOfBase()), temp1);
masm.storePtr(temp1, backtrackStackBaseAddress);
masm.addPtr(temp1, backtrack_stack_pointer);
@ -1050,7 +1050,7 @@ NativeRegExpMacroAssembler::CheckBacktrackStackLimit()
{
JitSpew(SPEW_PREFIX "CheckBacktrackStackLimit");
const void *limitAddr = runtime->mainThread.regexpStack.addressOfLimit();
const void *limitAddr = runtime->regexpStack.addressOfLimit();
Label no_stack_overflow;
masm.branchPtr(Assembler::AboveOrEqual, AbsoluteAddress(limitAddr),

View File

@ -36,7 +36,7 @@ using namespace js;
using namespace js::irregexp;
RegExpStackScope::RegExpStackScope(JSRuntime *rt)
: regexp_stack(&rt->mainThread.regexpStack)
: regexp_stack(&rt->regexpStack)
{}
RegExpStackScope::~RegExpStackScope()
@ -47,7 +47,7 @@ RegExpStackScope::~RegExpStackScope()
int
irregexp::GrowBacktrackStack(JSRuntime *rt)
{
return rt->mainThread.regexpStack.grow();
return rt->regexpStack.grow();
}
RegExpStack::RegExpStack()

View File

@ -0,0 +1,38 @@
// The bug was that the asm.js linker did not catch that an unshared
// view was created on a shared buffer. (Nor did it catch the vice
// versa case.) As a consequence the code was not rejected (and run
// as plain JS) as it should be. That gave rise to a difference in
// output.
// Original test
g = (function(stdlib, n, heap) {
"use asm";
var Float32ArrayView = new stdlib.Float32Array(heap);
function f() {
return +Float32ArrayView[0]
}
return f
})(this, {}, new SharedArrayBuffer(4096));
assertEq(g(), NaN);
// Additional test: vice versa case.
try {
g = (function(stdlib, n, heap) {
"use asm";
var Float32ArrayView = new stdlib.SharedFloat32Array(heap);
function f() {
return +Float32ArrayView[0]
}
return f
})(this, {}, new ArrayBuffer(4096));
// If the code runs, as it would with the bug present, it must return NaN.
assertEq(g(), NaN);
}
catch (e) {
// If the code throws then that's OK too. The current (January 2015)
// semantics is for the SharedFloat32Array constructor to throw if
// handed an ArrayBuffer, but asm.js does not execute that constructor
// and before the fix it would not throw.
}

View File

@ -0,0 +1,7 @@
// A resumption value can't have both {return:} and {throw:} properties.
var g = newGlobal();
var dbg = Debugger(g);
dbg.onDebuggerStatement = stack => ({return: 1, throw: 2});
dbg.uncaughtExceptionHook = exc => ({return: "corrected"});
assertEq(g.eval("debugger; false;"), "corrected");

View File

@ -0,0 +1,16 @@
// Error handling if parsing a resumption value throws.
var g = newGlobal();
var dbg = Debugger(g);
var rv;
dbg.onDebuggerStatement = stack => rv;
dbg.uncaughtExceptionHook = function (exc) {
assertEq(exc, "BANG");
return {return: "recovered"};
};
rv = {get throw() { throw "BANG"; }};
assertEq(g.eval("debugger; false;"), "recovered");
rv = new Proxy({}, {has() { throw "BANG"; }});
assertEq(g.eval("debugger; false;"), "recovered");

View File

@ -0,0 +1,108 @@
if (typeof SIMD === "undefined")
quit();
setJitCompilerOption("baseline.warmup.trigger", 10);
setJitCompilerOption("ion.warmup.trigger", 30);
var max = 40, pivot = 35;
var i32x4 = SIMD.int32x4;
var f32x4 = SIMD.float32x4;
var i32x4Add = SIMD.int32x4.add;
var FakeSIMDType = function (o) { this.x = o.x; this.y = o.y; this.z = o.z; this.w = o.w; };
if (this.hasOwnProperty("TypedObject")) {
var TO = TypedObject;
FakeSIMDType = new TO.StructType({ x: TO.int32, y: TO.int32, z: TO.int32, w: TO.int32 });
}
function simdunbox_bail_undef(i, lhs, rhs) {
return i32x4Add(lhs, rhs);
}
function simdunbox_bail_object(i, lhs, rhs) {
return i32x4Add(lhs, rhs);
}
function simdunbox_bail_typeobj(i, lhs, rhs) {
return i32x4Add(lhs, rhs);
}
function simdunbox_bail_badsimd(i, lhs, rhs) {
return i32x4Add(lhs, rhs);
}
var arr_undef = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
var fail_undef = 0;
var arr_object = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
var fail_object = 0;
var arr_typeobj = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
var fail_typeobj = 0;
var arr_badsimd = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
var fail_badsimd = 0;
for (var i = 0; i < max; i++) {
try {
arr_undef[i + 2] = simdunbox_bail_undef(i, arr_undef[i], arr_undef[i + 1]);
} catch (x) {
arr_undef[i + 2] = arr_undef[i - 1];
fail_undef++;
}
try {
arr_object[i + 2] = simdunbox_bail_object(i, arr_object[i], arr_object[i + 1]);
} catch (x) {
arr_object[i + 2] = arr_object[i - 1];
fail_object++;
}
try {
arr_typeobj[i + 2] = simdunbox_bail_typeobj(i, arr_typeobj[i], arr_typeobj[i + 1]);
} catch (x) {
arr_typeobj[i + 2] = arr_typeobj[i - 1];
fail_typeobj++;
}
try {
arr_badsimd[i + 2] = simdunbox_bail_badsimd(i, arr_badsimd[i], arr_badsimd[i + 1]);
} catch (x) {
arr_badsimd[i + 2] = arr_badsimd[i - 1];
fail_badsimd++;
}
if (i + 2 == pivot) {
arr_undef[pivot] = undefined;
arr_object[pivot] = { x: 0, y: 1, z: 2, w: 3 };
arr_typeobj[pivot] = new FakeSIMDType({ x: 0, y: 1, z: 2, w: 3 });
arr_badsimd[pivot] = f32x4(0, 1, 2, 3);
}
}
assertEq(fail_undef, 2);
assertEq(fail_object, 2);
assertEq(fail_typeobj, 2);
assertEq(fail_badsimd, 2);
// Assert that all SIMD values are correct.
function assertEqX4(real, expected, assertFunc) {
if (typeof assertFunc === 'undefined')
assertFunc = assertEq;
assertFunc(real.x, expected[0]);
assertFunc(real.y, expected[1]);
assertFunc(real.z, expected[2]);
assertFunc(real.w, expected[3]);
}
var fib = [0, 1];
for (i = 0; i < max + 5; i++)
fib[i+2] = (fib[i] + fib[i+1]) | 0;
for (i = 0; i < max; i++) {
if (i == pivot)
continue;
var ref = fib.slice(i < pivot ? i : i - 3);
assertEqX4(arr_undef[i], ref);
assertEqX4(arr_object[i], ref);
assertEqX4(arr_typeobj[i], ref);
assertEqX4(arr_badsimd[i], ref);
}

View File

@ -4,11 +4,33 @@ var i;
// Check that an entry frame is always aligned properly.
function entryFrame_1() {
assertValidJitStack();
assertJitStackInvariants();
}
// Check rectifier frames are keeping the same alignment.
function rectifierFrame_verify(a, b, c, d) {
assertJitStackInvariants();
}
function rectifierFrame_1(i) {
rectifierFrame_verify();
}
function rectifierFrame_2(i) {
rectifierFrame_verify(i);
}
function rectifierFrame_3(i) {
rectifierFrame_verify(i, i);
}
function rectifierFrame_4(i) {
rectifierFrame_verify(i, i, i);
}
for (i = 0; i < 40; i++) {
entryFrame_1();
entryFrame_1(0);
entryFrame_1(0, 1);
rectifierFrame_1(i);
rectifierFrame_2(i);
rectifierFrame_3(i);
rectifierFrame_4(i);
}

View File

@ -0,0 +1,16 @@
// Getting a property that exists on an ordinary object
// does not touch a proxy on its proto chain.
load(libdir + "asserts.js");
var angryHandler = new Proxy({}, {
get(t, id) { throw new Error("angryHandler should not be queried (" + id + ")"); }
});
var angryProto = new Proxy({}, angryHandler);
var obj = Object.create(angryProto, {
x: {value: 3},
y: {get: () => 4}
});
assertThrowsInstanceOf(() => obj.z, Error); // check that angryProto works
assertEq(obj.x, 3);
assertEq(obj.y, 4);

View File

@ -0,0 +1,31 @@
// Getting a property that's inherted from a proxy calls the proxy's get handler.
var handler = {
get(t, id, r) {
assertEq(this, handler);
assertEq(t, target);
assertEq(id, "foo");
assertEq(r, obj);
return "bar";
},
getOwnPropertyDescriptor(t, id) {
throw "FAIL";
}
};
var target = {};
var proto = new Proxy(target, handler);
var obj = Object.create(proto);
assertEq(obj.foo, "bar");
// Longer proto chain: same result.
var origObj = obj;
for (var i = 0; i < 4; i++)
obj = Object.create(obj);
assertEq(obj.foo, "bar");
// Chain of transparent proxy wrappers: same result.
obj = origObj;
for (var i = 0; i < 4; i++)
obj = new Proxy(obj, {});
assertEq(obj.foo, "bar");

View File

@ -0,0 +1,21 @@
// Recursion through the get hook works; runaway recursion is checked.
load(libdir + "asserts.js");
var hits = 0, limit = 10;
var proto = new Proxy({}, {
get(t, id, r) {
assertEq(r, obj);
if (hits++ >= limit)
return "ding";
return obj[id];
}
});
var obj = Object.create(proto);
assertEq(obj.prop, "ding");
hits = 0;
limit = Infinity;
assertThrowsInstanceOf(() => obj.prop, InternalError);
assertEq(hits > 10, true);

View File

@ -0,0 +1,6 @@
// A proxy P whose target is an object X whose prototype is an array V inherits V.length.
var V = [1, 2, 3];
var X = Object.create(V);
var P = new Proxy(X, {});
assertEq(P.length, 3);

View File

@ -0,0 +1,18 @@
// Getting a property O.X, inherited from a transparent cross-compartment wrapper W
// that wraps a Proxy P.
var g = newGlobal();
var target = {}
var P = new Proxy(target, {
get(t, id, r) {
assertEq(t, target);
assertEq(id, "X");
assertEq(r, wO);
return "vega";
}
});
g.W = P;
g.eval("var O = Object.create(W);");
var wO = g.O;
assertEq(g.eval("O.X"), "vega");

View File

@ -101,6 +101,7 @@ BacktrackingAllocator::go()
dumpRegisterGroups();
JitSpew(JitSpew_RegAlloc, "Beginning main allocation loop");
// Allocate, spill and split register intervals until finished.
while (!allocationQueue.empty()) {
if (mir->shouldCancel("Backtracking Allocation"))
@ -112,10 +113,22 @@ BacktrackingAllocator::go()
}
JitSpew(JitSpew_RegAlloc, "Main allocation loop complete");
if (!pickStackSlots())
return false;
if (JitSpewEnabled(JitSpew_RegAlloc))
dumpAllocations();
return resolveControlFlow() && reifyAllocations() && populateSafepoints();
if (!resolveControlFlow())
return false;
if (!reifyAllocations())
return false;
if (!populateSafepoints())
return false;
return true;
}
static bool
@ -383,6 +396,7 @@ BacktrackingAllocator::groupAndQueueRegisters()
// for that slot, and reuse it for other registers in the group.
LDefinition *def = reg.def();
if (def->policy() == LDefinition::FIXED && !def->output()->isRegister()) {
MOZ_ASSERT(!def->output()->isStackSlot());
reg.setCanonicalSpill(*def->output());
if (reg.group() && reg.group()->spill.isUse())
reg.group()->spill = *def->output();
@ -930,10 +944,11 @@ BacktrackingAllocator::spill(LiveInterval *interval)
}
}
uint32_t stackSlot = stackSlotAllocator.allocateSlot(reg->type());
MOZ_ASSERT(stackSlot <= stackSlotAllocator.stackHeight());
uint32_t virtualSlot = numVirtualStackSlots++;
LStackSlot alloc(stackSlot);
// Count virtual stack slots down from the maximum representable value, so
// that virtual slots are more obviously distinguished from real slots.
LStackSlot alloc(LAllocation::DATA_MASK - virtualSlot);
interval->setAllocation(alloc);
JitSpew(JitSpew_RegAlloc, " Allocating spill location %s", alloc.toString());
@ -945,6 +960,179 @@ BacktrackingAllocator::spill(LiveInterval *interval)
}
}
bool
BacktrackingAllocator::pickStackSlots()
{
for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
BacktrackingVirtualRegister *reg = &vregs[i];
if (mir->shouldCancel("Backtracking Pick Stack Slots"))
return false;
for (size_t j = 0; j < reg->numIntervals(); j++) {
LiveInterval *interval = reg->getInterval(j);
if (!pickStackSlot(interval))
return false;
}
}
return true;
}
bool
BacktrackingAllocator::pickStackSlot(LiveInterval *interval)
{
LAllocation alloc = *interval->getAllocation();
MOZ_ASSERT(!alloc.isUse());
if (!isVirtualStackSlot(alloc))
return true;
BacktrackingVirtualRegister &reg = vregs[interval->vreg()];
// Get a list of all the intervals which will share this stack slot.
LiveIntervalVector commonIntervals;
if (!commonIntervals.append(interval))
return false;
if (reg.canonicalSpill() && alloc == *reg.canonicalSpill()) {
// Look for other intervals in the vreg using this spill slot.
for (size_t i = 0; i < reg.numIntervals(); i++) {
LiveInterval *ninterval = reg.getInterval(i);
if (ninterval != interval && *ninterval->getAllocation() == alloc) {
if (!commonIntervals.append(ninterval))
return false;
}
}
// Look for intervals in other registers with the same group using this
// spill slot.
if (reg.group() && alloc == reg.group()->spill) {
for (size_t i = 0; i < reg.group()->registers.length(); i++) {
uint32_t nvreg = reg.group()->registers[i];
if (nvreg == interval->vreg())
continue;
BacktrackingVirtualRegister &nreg = vregs[nvreg];
for (size_t j = 0; j < nreg.numIntervals(); j++) {
LiveInterval *ninterval = nreg.getInterval(j);
if (*ninterval->getAllocation() == alloc) {
if (!commonIntervals.append(ninterval))
return false;
}
}
}
}
} else {
MOZ_ASSERT_IF(reg.group(), alloc != reg.group()->spill);
}
if (!reuseOrAllocateStackSlot(commonIntervals, reg.type(), &alloc))
return false;
MOZ_ASSERT(!isVirtualStackSlot(alloc));
// Set the physical stack slot for each of the intervals found earlier.
for (size_t i = 0; i < commonIntervals.length(); i++)
commonIntervals[i]->setAllocation(alloc);
return true;
}
bool
BacktrackingAllocator::reuseOrAllocateStackSlot(const LiveIntervalVector &intervals, LDefinition::Type type,
LAllocation *palloc)
{
SpillSlotList *slotList;
switch (StackSlotAllocator::width(type)) {
case 4: slotList = &normalSlots; break;
case 8: slotList = &doubleSlots; break;
case 16: slotList = &quadSlots; break;
default:
MOZ_CRASH("Bad width");
}
// Maximum number of existing spill slots we will look at before giving up
// and allocating a new slot.
static const size_t MAX_SEARCH_COUNT = 10;
if (!slotList->empty()) {
size_t searches = 0;
SpillSlot *stop = nullptr;
while (true) {
SpillSlot *spill = *slotList->begin();
if (!stop) {
stop = spill;
} else if (stop == spill) {
// We looked through every slot in the list.
break;
}
bool success = true;
for (size_t i = 0; i < intervals.length() && success; i++) {
LiveInterval *interval = intervals[i];
for (size_t j = 0; j < interval->numRanges(); j++) {
AllocatedRange range(interval, interval->getRange(j)), existing;
if (spill->allocated.contains(range, &existing)) {
success = false;
break;
}
}
}
if (success) {
// We can reuse this physical stack slot for the new intervals.
// Update the allocated ranges for the slot.
if (!insertAllRanges(spill->allocated, intervals))
return false;
*palloc = spill->alloc;
return true;
}
// On a miss, move the spill to the end of the list. This will cause us
// to make fewer attempts to allocate from slots with a large and
// highly contended range.
slotList->popFront();
slotList->pushBack(spill);
if (++searches == MAX_SEARCH_COUNT)
break;
}
}
// We need a new physical stack slot.
uint32_t stackSlot = stackSlotAllocator.allocateSlot(type);
// Make sure the virtual and physical stack slots don't start overlapping.
if (isVirtualStackSlot(LStackSlot(stackSlot)))
return false;
SpillSlot *spill = new(alloc()) SpillSlot(stackSlot, alloc().lifoAlloc());
if (!spill)
return false;
if (!insertAllRanges(spill->allocated, intervals))
return false;
*palloc = spill->alloc;
slotList->pushFront(spill);
return true;
}
bool
BacktrackingAllocator::insertAllRanges(AllocatedRangeSet &set, const LiveIntervalVector &intervals)
{
for (size_t i = 0; i < intervals.length(); i++) {
LiveInterval *interval = intervals[i];
for (size_t j = 0; j < interval->numRanges(); j++) {
AllocatedRange range(interval, interval->getRange(j));
if (!set.insert(range))
return false;
}
}
return true;
}
// Add moves to resolve conflicting assignments between a block and its
// predecessors. XXX try to common this with LinearScanAllocator.
bool

View File

@ -176,9 +176,28 @@ class BacktrackingAllocator
// should be prioritized.
AllocatedRangeSet hotcode;
// During register allocation, virtual stack slots are used for spills.
// These are converted to actual spill locations
size_t numVirtualStackSlots;
// Information about an allocated stack slot.
struct SpillSlot : public TempObject, public InlineForwardListNode<SpillSlot> {
LStackSlot alloc;
AllocatedRangeSet allocated;
SpillSlot(uint32_t slot, LifoAlloc *alloc)
: alloc(slot), allocated(alloc)
{}
};
typedef InlineForwardList<SpillSlot> SpillSlotList;
// All allocated slots of each width.
SpillSlotList normalSlots, doubleSlots, quadSlots;
public:
BacktrackingAllocator(MIRGenerator *mir, LIRGenerator *lir, LIRGraph &graph)
: LiveRangeAllocator<BacktrackingVirtualRegister, /* forLSRA = */ false>(mir, lir, graph)
: LiveRangeAllocator<BacktrackingVirtualRegister, /* forLSRA = */ false>(mir, lir, graph),
numVirtualStackSlots(0)
{ }
bool go();
@ -213,7 +232,12 @@ class BacktrackingAllocator
bool addLiveInterval(LiveIntervalVector &intervals, uint32_t vreg,
LiveInterval *spillInterval,
CodePosition from, CodePosition to);
bool pickStackSlot(LiveInterval *interval);
bool reuseOrAllocateStackSlot(const LiveIntervalVector &intervals, LDefinition::Type type,
LAllocation *palloc);
bool insertAllRanges(AllocatedRangeSet &set, const LiveIntervalVector &intervals);
bool pickStackSlots();
bool resolveControlFlow();
bool reifyAllocations();
bool populateSafepoints();
@ -249,6 +273,11 @@ class BacktrackingAllocator
bool compilingAsmJS() {
return mir->info().compilingAsmJS();
}
bool isVirtualStackSlot(LAllocation alloc) {
return alloc.isStackSlot() &&
LAllocation::DATA_MASK - alloc.toStackSlot()->slot() < numVirtualStackSlots;
}
};
} // namespace jit

View File

@ -34,7 +34,7 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
"Fake jitTop pointer should be within the first page.");
cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
cx->runtime()->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
JitActivationIterator jitActivations(cx->runtime());
BailoutFrameInfo bailoutData(jitActivations, sp);
@ -94,7 +94,7 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
// In both cases, we want to temporarily set the |lastProfilingFrame|
// to the current frame being bailed out, and then fix it up later.
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
cx->mainThread().jitActivation->setLastProfilingFrame(currentFramePtr);
cx->runtime()->jitActivation->setLastProfilingFrame(currentFramePtr);
return retval;
}
@ -108,7 +108,7 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
JSContext *cx = GetJSContextFromJitCode();
// We don't have an exit frame.
cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
cx->runtime()->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
JitActivationIterator jitActivations(cx->runtime());
BailoutFrameInfo bailoutData(jitActivations, sp);
@ -168,7 +168,7 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
// Make the frame being bailed out the top profiled frame.
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
cx->mainThread().jitActivation->setLastProfilingFrame(currentFramePtr);
cx->runtime()->jitActivation->setLastProfilingFrame(currentFramePtr);
return retval;
}
@ -197,7 +197,7 @@ jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
// operation callback like a timeout handler.
MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending());
cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
cx->runtime()->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
gc::AutoSuppressGC suppress(cx);
JitActivationIterator jitActivations(cx->runtime());
@ -238,7 +238,7 @@ jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
// Make the frame being bailed out the top profiled frame.
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
cx->mainThread().jitActivation->setLastProfilingFrame(currentFramePtr);
cx->runtime()->jitActivation->setLastProfilingFrame(currentFramePtr);
return retval;
}

View File

@ -1654,7 +1654,7 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo)
// (which must be a baseline frame), and set it as the last profiling
// frame.
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
cx->mainThread().jitActivation->setLastProfilingFrame(iter.prevFp());
cx->runtime()->jitActivation->setLastProfilingFrame(iter.prevFp());
uint32_t frameno = 0;
while (frameno < numFrames) {
@ -1707,7 +1707,7 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo)
// values into the baseline frame. We need to do this even when debug mode
// is off, as we should respect the mutations made while debug mode was
// on.
JitActivation *act = cx->mainThread().activation()->asJit();
JitActivation *act = cx->runtime()->activation()->asJit();
if (act->hasRematerializedFrame(outerFp)) {
JitFrameIterator iter(cx);
size_t inlineDepth = numFrames;
@ -1754,6 +1754,8 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo)
case Bailout_NonObjectInput:
case Bailout_NonStringInput:
case Bailout_NonSymbolInput:
case Bailout_NonSimdInt32x4Input:
case Bailout_NonSimdFloat32x4Input:
case Bailout_InitialState:
case Bailout_Debugger:
// Do nothing.

View File

@ -512,7 +512,7 @@ bool
BaselineCompiler::emitStackCheck(bool earlyCheck)
{
Label skipCall;
void *limitAddr = cx->runtime()->mainThread.addressOfJitStackLimit();
void *limitAddr = cx->runtime()->addressOfJitStackLimit();
uint32_t slotsSize = script->nslots() * sizeof(Value);
uint32_t tolerance = earlyCheck ? slotsSize : 0;
@ -3644,7 +3644,7 @@ BaselineCompiler::emit_JSOP_RESUME()
Label skip;
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skip);
masm.loadPtr(AbsoluteAddress(cx->mainThread().addressOfProfilingActivation()), scratchReg);
masm.loadPtr(AbsoluteAddress(cx->runtime()->addressOfProfilingActivation()), scratchReg);
masm.storePtr(BaselineStackReg,
Address(scratchReg, JitActivation::offsetOfLastProfilingFrame()));
masm.bind(&skip);

View File

@ -14,6 +14,7 @@
#include "jstypes.h"
#include "builtin/Eval.h"
#include "builtin/SIMD.h"
#include "jit/BaselineDebugModeOSR.h"
#include "jit/BaselineHelpers.h"
#include "jit/BaselineJIT.h"
@ -1013,7 +1014,7 @@ ICWarmUpCounter_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
Label checkOk;
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &checkOk);
masm.loadPtr(AbsoluteAddress((void*)&cx->mainThread().jitActivation), scratchReg);
masm.loadPtr(AbsoluteAddress((void*)&cx->runtime()->jitActivation), scratchReg);
masm.loadPtr(Address(scratchReg, JitActivation::offsetOfLastProfilingFrame()), scratchReg);
// It may be the case that we entered the baseline frame with
@ -8840,7 +8841,7 @@ TryAttachFunCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script,
static bool
GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
Native native, const CallArgs &args, MutableHandleNativeObject res)
Native native, const CallArgs &args, MutableHandleObject res)
{
// Check for natives to which template objects can be attached. This is
// done to provide templates to Ion for inlining these natives later on.
@ -8917,6 +8918,14 @@ GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
return true;
}
if (native == js::simd_int32x4_add && JitSupportsSimd()) {
Rooted<TypeDescr *> descr(cx, &Int32x4::GetTypeDescr(*cx->global()));
res.set(TypedObject::createZeroed(cx, descr, 0, gc::TenuredHeap));
if (!res)
return false;
return true;
}
return true;
}
@ -9151,7 +9160,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
return true;
}
RootedNativeObject templateObject(cx);
RootedObject templateObject(cx);
if (MOZ_LIKELY(!isSpread)) {
CallArgs args = CallArgsFromVp(argc, vp);
if (!GetTemplateObjectForNative(cx, script, pc, fun->native(), args, &templateObject))
@ -11741,7 +11750,7 @@ ICCall_AnyScripted::Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorS
}
ICCall_Native::ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
HandleFunction callee, HandleNativeObject templateObject,
HandleFunction callee, HandleObject templateObject,
uint32_t pcOffset)
: ICMonitoredStub(ICStub::Call_Native, stubCode, firstMonitorStub),
callee_(callee),
@ -11762,7 +11771,7 @@ ICCall_Native::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub
ICCall_Native &other)
{
RootedFunction callee(cx, other.callee_);
RootedNativeObject templateObject(cx, other.templateObject_);
RootedObject templateObject(cx, other.templateObject_);
return New(space, other.jitCode(), firstMonitorStub, callee, templateObject,
other.pcOffset_);
}

View File

@ -5921,7 +5921,7 @@ class ICCall_Native : public ICMonitoredStub
protected:
HeapPtrFunction callee_;
HeapPtrNativeObject templateObject_;
HeapPtrObject templateObject_;
uint32_t pcOffset_;
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
@ -5929,12 +5929,12 @@ class ICCall_Native : public ICMonitoredStub
#endif
ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
HandleFunction callee, HandleNativeObject templateObject,
HandleFunction callee, HandleObject templateObject,
uint32_t pcOffset);
public:
static inline ICCall_Native *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
HandleFunction callee, HandleNativeObject templateObject,
HandleFunction callee, HandleObject templateObject,
uint32_t pcOffset)
{
if (!code)
@ -5949,7 +5949,7 @@ class ICCall_Native : public ICMonitoredStub
HeapPtrFunction &callee() {
return callee_;
}
HeapPtrNativeObject &templateObject() {
HeapPtrObject &templateObject() {
return templateObject_;
}
@ -5973,7 +5973,7 @@ class ICCall_Native : public ICMonitoredStub
bool isConstructing_;
bool isSpread_;
RootedFunction callee_;
RootedNativeObject templateObject_;
RootedObject templateObject_;
uint32_t pcOffset_;
bool generateStubCode(MacroAssembler &masm);
@ -5984,7 +5984,7 @@ class ICCall_Native : public ICMonitoredStub
public:
Compiler(JSContext *cx, ICStub *firstMonitorStub,
HandleFunction callee, HandleNativeObject templateObject,
HandleFunction callee, HandleObject templateObject,
bool isConstructing, bool isSpread, uint32_t pcOffset)
: ICCallStubCompiler(cx, ICStub::Call_Native),
firstMonitorStub_(firstMonitorStub),

View File

@ -440,7 +440,7 @@ BaselineInspector::getTemplateObject(jsbytecode *pc)
return nullptr;
}
NativeObject *
JSObject *
BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
{
if (!hasBaselineScript())

View File

@ -110,7 +110,7 @@ class BaselineInspector
bool hasSeenNonStringIterMore(jsbytecode *pc);
NativeObject *getTemplateObject(jsbytecode *pc);
NativeObject *getTemplateObjectForNative(jsbytecode *pc, Native native);
JSObject *getTemplateObjectForNative(jsbytecode *pc, Native native);
JSObject *getTemplateObjectForClassHook(jsbytecode *pc, const Class *clasp);
DeclEnvObject *templateDeclEnvObject();

View File

@ -3075,25 +3075,17 @@ CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric *apply)
masm.checkStackAlignment();
// If the function is known to be uncompilable, only emit the call to InvokeFunction.
if (apply->hasSingleTarget()) {
JSFunction *target = apply->getSingleTarget();
if (target->isNative()) {
emitCallInvokeFunction(apply, copyreg);
emitPopArguments(apply, copyreg);
return;
}
// If the function is native, only emit the call to InvokeFunction.
if (apply->hasSingleTarget() && apply->getSingleTarget()->isNative()) {
emitCallInvokeFunction(apply, copyreg);
emitPopArguments(apply, copyreg);
return;
}
Label end, invoke;
// Guard that calleereg is an interpreted function with a JSScript:
if (!apply->hasSingleTarget()) {
masm.branchIfFunctionHasNoScript(calleereg, &invoke);
} else {
// Native single targets are handled by LCallNative.
MOZ_ASSERT(!apply->getSingleTarget()->isNative());
}
// Guard that calleereg is an interpreted function with a JSScript.
masm.branchIfFunctionHasNoScript(calleereg, &invoke);
// Knowing that calleereg is a non-native function, load the JSScript.
masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
@ -4233,6 +4225,74 @@ CodeGenerator::visitSimdBox(LSimdBox *lir)
}
}
void
CodeGenerator::visitSimdUnbox(LSimdUnbox *lir)
{
Register object = ToRegister(lir->input());
FloatRegister simd = ToFloatRegister(lir->output());
Register temp = ToRegister(lir->temp());
Label bail;
// obj->type()
masm.loadPtr(Address(object, JSObject::offsetOfType()), temp);
// Guard that the object has the same representation as the one produced for
// SIMD value-type.
Address clasp(temp, types::TypeObject::offsetOfClasp());
static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent");
masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_),
&bail);
// obj->type()->typeDescr()
// The previous class pointer comparison implies that the addendumKind is
// Addendum_TypeDescr.
masm.loadPtr(Address(temp, types::TypeObject::offsetOfAddendum()), temp);
// Check for the /Kind/ reserved slot of the TypeDescr. This is an Int32
// Value which is equivalent to the object class check.
static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
Address typeDescrKind(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND));
masm.assertTestInt32(Assembler::Equal, typeDescrKind,
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())");
masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrKind), Imm32(js::type::Simd), &bail);
// Convert the SIMD MIRType to a SimdTypeDescr::Type.
js::SimdTypeDescr::Type type;
switch (lir->mir()->type()) {
case MIRType_Int32x4:
type = js::SimdTypeDescr::TYPE_INT32;
break;
case MIRType_Float32x4:
type = js::SimdTypeDescr::TYPE_FLOAT32;
break;
default:
MOZ_CRASH("Unexpected SIMD Type.");
}
// Check if the SimdTypeDescr /Type/ match the specialization of this
// MSimdUnbox instruction.
static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
Address typeDescrType(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE));
masm.assertTestInt32(Assembler::Equal, typeDescrType,
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())");
masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrType), Imm32(type), &bail);
// Load the value from the data of the InlineTypedObject.
Address objectData(object, InlineTypedObject::offsetOfDataStart());
switch (lir->mir()->type()) {
case MIRType_Int32x4:
masm.loadUnalignedInt32x4(objectData, simd);
break;
case MIRType_Float32x4:
masm.loadUnalignedFloat32x4(objectData, simd);
break;
default:
MOZ_CRASH("The impossible happened!");
}
bailoutFrom(&bail, lir->snapshot());
}
typedef js::DeclEnvObject *(*NewDeclEnvObjectFn)(JSContext *, HandleFunction, gc::InitialHeap);
static const VMFunction NewDeclEnvObjectInfo =
FunctionInfo<NewDeclEnvObjectFn>(DeclEnvObject::createTemplateObject);

View File

@ -156,6 +156,7 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitOutOfLineNewObject(OutOfLineNewObject *ool);
void visitNewTypedObject(LNewTypedObject *lir);
void visitSimdBox(LSimdBox *lir);
void visitSimdUnbox(LSimdUnbox *lir);
void visitNewDeclEnvObject(LNewDeclEnvObject *lir);
void visitNewCallObject(LNewCallObject *lir);
void visitNewSingletonCallObject(LNewSingletonCallObject *lir);

View File

@ -37,37 +37,37 @@ CompileRuntime::mainThread()
const void *
CompileRuntime::addressOfJitTop()
{
return &runtime()->mainThread.jitTop;
return &runtime()->jitTop;
}
const void *
CompileRuntime::addressOfJitActivation()
{
return &runtime()->mainThread.jitActivation;
return &runtime()->jitActivation;
}
const void *
CompileRuntime::addressOfProfilingActivation()
{
return (const void *) &runtime()->mainThread.profilingActivation_;
return (const void *) &runtime()->profilingActivation_;
}
const void *
CompileRuntime::addressOfJitStackLimit()
{
return runtime()->mainThread.addressOfJitStackLimit();
return runtime()->addressOfJitStackLimit();
}
const void *
CompileRuntime::addressOfJSContext()
{
return &runtime()->mainThread.jitJSContext;
return &runtime()->jitJSContext;
}
const void *
CompileRuntime::addressOfActivation()
{
return runtime()->mainThread.addressOfActivation();
return runtime()->addressOfActivation();
}
const void *

View File

@ -31,22 +31,22 @@ class CompileRuntime
js::PerThreadData *mainThread();
// &mainThread.jitTop
// &runtime()->jitTop
const void *addressOfJitTop();
// &mainThread.jitActivation
// &runtime()->jitActivation
const void *addressOfJitActivation();
// &mainThread.profilingActivation
// &runtime()->profilingActivation
const void *addressOfProfilingActivation();
// rt->mainThread.jitStackLimit;
// rt->runtime()->jitStackLimit;
const void *addressOfJitStackLimit();
// &mainThread.jitJSContext
// &runtime()->jitJSContext
const void *addressOfJSContext();
// &mainThread.activation_
// &runtime()->activation_
const void *addressOfActivation();
// &GetJitContext()->runtime->nativeIterCache.last

View File

@ -788,7 +788,11 @@ class IonBuilder
bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
ScalarTypeDescr::Type *arrayType);
InliningStatus inlineConstructTypedObject(CallInfo &callInfo, TypeDescr *target);
// SIMD intrinsics and natives.
InliningStatus inlineConstructSimdObject(CallInfo &callInfo, SimdTypeDescr *target);
InliningStatus inlineSimdInt32x4BinaryArith(CallInfo &callInfo, JSNative native,
MSimdBinaryArith::Operation op);
// Utility intrinsics.
InliningStatus inlineIsCallable(CallInfo &callInfo);

View File

@ -100,6 +100,10 @@ enum BailoutKind
Bailout_NonStringInput,
Bailout_NonSymbolInput,
// SIMD Unbox expects a given type, bails out if it doesn't match.
Bailout_NonSimdInt32x4Input,
Bailout_NonSimdFloat32x4Input,
// For the initial snapshot when entering a function.
Bailout_InitialState,
@ -193,6 +197,10 @@ BailoutKindString(BailoutKind kind)
return "Bailout_NonStringInput";
case Bailout_NonSymbolInput:
return "Bailout_NonSymbolInput";
case Bailout_NonSimdInt32x4Input:
return "Bailout_NonSimdInt32x4Input";
case Bailout_NonSimdFloat32x4Input:
return "Bailout_NonSimdFloat32x4Input";
case Bailout_InitialState:
return "Bailout_InitialState";
case Bailout_Debugger:

View File

@ -89,8 +89,9 @@ class BaselineFrame;
class JitActivation;
// Iterate over the JIT stack to assert that all invariants are respected.
// - Check that all entry frames are aligned on StackAlignment.
void AssertValidJitStack(JSContext *cx);
// - Check that all entry frames are aligned on JitStackAlignment.
// - Check that all rectifier frames keep the JitStackAlignment.
void AssertJitStackInvariants(JSContext *cx);
class JitFrameIterator
{

View File

@ -98,12 +98,12 @@ JitFrameIterator::JitFrameIterator()
}
JitFrameIterator::JitFrameIterator(JSContext *cx)
: current_(cx->perThreadData->jitTop),
: current_(cx->runtime()->jitTop),
type_(JitFrame_Exit),
returnAddressToFp_(nullptr),
frameSize_(0),
cachedSafepointIndex_(nullptr),
activation_(cx->perThreadData->activation()->asJit())
activation_(cx->runtime()->activation()->asJit())
{
if (activation_->bailoutData()) {
current_ = activation_->bailoutData()->fp();
@ -390,7 +390,7 @@ HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromEx
// Debugger has observed this frame (e.g., for onPop).
bool shouldBail = Debugger::hasLiveHook(cx->global(), Debugger::OnExceptionUnwind);
if (!shouldBail) {
JitActivation *act = cx->mainThread().activation()->asJit();
JitActivation *act = cx->runtime()->activation()->asJit();
RematerializedFrame *rematFrame =
act->lookupRematerializedFrame(frame.frame().fp(), frame.frameNo());
shouldBail = rematFrame && rematFrame->isDebuggee();
@ -693,10 +693,10 @@ struct AutoResetLastProfilerFrameOnReturnFromException
if (!cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
return;
MOZ_ASSERT(cx->mainThread().jitActivation == cx->mainThread().profilingActivation());
MOZ_ASSERT(cx->runtime()->jitActivation == cx->runtime()->profilingActivation());
void *lastProfilingFrame = getLastProfilingFrame();
cx->mainThread().jitActivation->setLastProfilingFrame(lastProfilingFrame);
cx->runtime()->jitActivation->setLastProfilingFrame(lastProfilingFrame);
}
void *getLastProfilingFrame() {
@ -740,7 +740,7 @@ HandleException(ResumeFromException *rfe)
if (cx->runtime()->jitRuntime()->hasIonReturnOverride())
cx->runtime()->jitRuntime()->takeIonReturnOverride();
JitActivation *activation = cx->mainThread().activation()->asJit();
JitActivation *activation = cx->runtime()->activation()->asJit();
// The Debugger onExceptionUnwind hook (reachable via
// HandleExceptionBaseline below) may cause on-stack recompilation of
@ -863,7 +863,7 @@ HandleException(ResumeFromException *rfe)
// not crash when accessing an IonScript that's destroyed by the
// ionScript->decref call.
EnsureExitFrame(current);
cx->mainThread().jitTop = (uint8_t *)current;
cx->runtime()->jitTop = (uint8_t *)current;
}
if (overrecursed) {
@ -2737,16 +2737,16 @@ JitProfilingFrameIterator::JitProfilingFrameIterator(
{
// If no profilingActivation is live, initialize directly to
// end-of-iteration state.
if (!rt->mainThread.profilingActivation()) {
if (!rt->profilingActivation()) {
type_ = JitFrame_Entry;
fp_ = nullptr;
returnAddressToFp_ = nullptr;
return;
}
MOZ_ASSERT(rt->mainThread.profilingActivation()->isJit());
MOZ_ASSERT(rt->profilingActivation()->isJit());
JitActivation *act = rt->mainThread.profilingActivation()->asJit();
JitActivation *act = rt->profilingActivation()->asJit();
// If the top JitActivation has a null lastProfilingFrame, assume that
// it's a trivially empty activation, and initialize directly
@ -3026,12 +3026,30 @@ InvalidationBailoutStack::checkInvariants() const
}
void
AssertValidJitStack(JSContext *cx)
AssertJitStackInvariants(JSContext *cx)
{
for (JitActivationIterator activations(cx->runtime()); !activations.done(); ++activations) {
JitFrameIterator frames(activations);
for (; !frames.done(); ++frames)
continue;
for (; !frames.done(); ++frames) {
if (frames.prevType() == JitFrame_Rectifier) {
size_t calleeFp = reinterpret_cast<size_t>(frames.fp());
size_t callerFp = reinterpret_cast<size_t>(frames.prevFp());
MOZ_ASSERT(callerFp >= calleeFp);
size_t frameSize = callerFp - calleeFp;
MOZ_RELEASE_ASSERT(frameSize % JitStackAlignment == 0,
"The rectifier frame should keep the alignment");
size_t expectedFrameSize = 0
+ sizeof(Value) * (frames.callee()->nargs() + 1 /* |this| argument */ )
+ sizeof(JitFrameLayout);
MOZ_RELEASE_ASSERT(frameSize >= expectedFrameSize,
"The frame is large enough to hold all arguments");
MOZ_RELEASE_ASSERT(expectedFrameSize + JitStackAlignment > frameSize,
"The frame size is optimal");
}
}
MOZ_RELEASE_ASSERT(frames.type() == JitFrame_Entry,
"The first frame of a Jit activation should be an entry frame");

View File

@ -157,6 +157,26 @@ class LSimdBox : public LInstructionHelper<1, 1, 1>
}
};
class LSimdUnbox : public LInstructionHelper<1, 1, 1>
{
public:
LIR_HEADER(SimdUnbox)
LSimdUnbox(const LAllocation &obj, const LDefinition &temp)
{
setOperand(0, obj);
setTemp(0, temp);
}
const LDefinition *temp() {
return getTemp(0);
}
MSimdUnbox *mir() const {
return mir_->toSimdUnbox();
}
};
// Constructs a SIMD value with 4 equal components (e.g. int32x4, float32x4).
class LSimdSplatX4 : public LInstructionHelper<1, 1, 0>
{

View File

@ -67,7 +67,6 @@ class LAllocation : public TempObject
protected:
static const uintptr_t DATA_BITS = (sizeof(uint32_t) * 8) - KIND_BITS;
static const uintptr_t DATA_SHIFT = KIND_SHIFT + KIND_BITS;
static const uintptr_t DATA_MASK = (1 << DATA_BITS) - 1;
public:
enum Kind {
@ -80,6 +79,8 @@ class LAllocation : public TempObject
ARGUMENT_SLOT // Argument slot.
};
static const uintptr_t DATA_MASK = (1 << DATA_BITS) - 1;
protected:
uint32_t data() const {
return uint32_t(bits_) >> DATA_SHIFT;

View File

@ -18,6 +18,7 @@
_(Double) \
_(Float32) \
_(SimdBox) \
_(SimdUnbox) \
_(SimdSplatX4) \
_(Int32x4) \
_(Float32x4) \

View File

@ -3734,6 +3734,30 @@ LIRGenerator::visitSimdBox(MSimdBox *ins)
define(lir, ins);
}
void
LIRGenerator::visitSimdUnbox(MSimdUnbox *ins)
{
MOZ_ASSERT(ins->input()->type() == MIRType_Object);
MOZ_ASSERT(IsSimdType(ins->type()));
LUse in = useRegister(ins->input());
BailoutKind kind;
switch (ins->type()) {
case MIRType_Int32x4:
kind = Bailout_NonSimdInt32x4Input;
break;
case MIRType_Float32x4:
kind = Bailout_NonSimdFloat32x4Input;
break;
default:
MOZ_CRASH("Unexpected SIMD Type.");
};
LSimdUnbox *lir = new(alloc()) LSimdUnbox(in, temp());
assignSnapshot(lir, kind);
define(lir, ins);
}
void
LIRGenerator::visitSimdConstant(MSimdConstant *ins)
{

View File

@ -266,6 +266,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitRecompileCheck(MRecompileCheck *ins);
void visitMemoryBarrier(MMemoryBarrier *ins);
void visitSimdBox(MSimdBox *ins);
void visitSimdUnbox(MSimdUnbox *ins);
void visitSimdExtractElement(MSimdExtractElement *ins);
void visitSimdInsertElement(MSimdInsertElement *ins);
void visitSimdSignMask(MSimdSignMask *ins);

View File

@ -7,6 +7,7 @@
#include "jsmath.h"
#include "builtin/AtomicsObject.h"
#include "builtin/SIMD.h"
#include "builtin/TestingFunctions.h"
#include "builtin/TypedObject.h"
#include "jit/BaselineInspector.h"
@ -246,6 +247,10 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
if (native == js::CallOrConstructBoundFunction)
return inlineBoundFunction(callInfo, target);
// Simd functions
if (native == js::simd_int32x4_add)
return inlineSimdInt32x4BinaryArith(callInfo, native, MSimdBinaryArith::Add);
return InliningStatus_NotInlined;
}
@ -349,17 +354,17 @@ IonBuilder::inlineArray(CallInfo &callInfo)
uint32_t initLength = 0;
AllocatingBehaviour allocating = NewArray_Unallocating;
NativeObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array);
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array);
if (!templateObject)
return InliningStatus_NotInlined;
MOZ_ASSERT(templateObject->is<ArrayObject>());
ArrayObject *templateArray = &templateObject->as<ArrayObject>();
// Multiple arguments imply array initialization, not just construction.
if (callInfo.argc() >= 2) {
initLength = callInfo.argc();
allocating = NewArray_FullyAllocating;
types::TypeObjectKey *type = types::TypeObjectKey::get(templateObject);
types::TypeObjectKey *type = types::TypeObjectKey::get(templateArray);
if (!type->unknownProperties()) {
types::HeapTypeSetKey elemTypes = type->property(JSID_VOID);
@ -376,9 +381,9 @@ IonBuilder::inlineArray(CallInfo &callInfo)
types::TemporaryTypeSet::DoubleConversion conversion =
getInlineReturnTypeSet()->convertDoubleElements(constraints());
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
templateObject->setShouldConvertDoubleElements();
templateArray->setShouldConvertDoubleElements();
else
templateObject->clearShouldConvertDoubleElements();
templateArray->clearShouldConvertDoubleElements();
// A single integer argument denotes initial length.
if (callInfo.argc() == 1) {
@ -388,7 +393,6 @@ IonBuilder::inlineArray(CallInfo &callInfo)
MDefinition *arg = callInfo.getArg(0);
if (!arg->isConstantValue()) {
callInfo.setImplicitlyUsedUnchecked();
ArrayObject *templateArray = &templateObject->as<ArrayObject>();
MNewArrayDynamicLength *ins =
MNewArrayDynamicLength::New(alloc(), constraints(), templateArray,
templateArray->type()->initialHeap(constraints()),
@ -406,7 +410,7 @@ IonBuilder::inlineArray(CallInfo &callInfo)
// Make sure initLength matches the template object's length. This is
// not guaranteed to be the case, for instance if we're inlining the
// MConstant may come from an outer script.
if (initLength != templateObject->as<ArrayObject>().length())
if (initLength != templateArray->as<ArrayObject>().length())
return InliningStatus_NotInlined;
// Don't inline large allocations.
@ -418,11 +422,11 @@ IonBuilder::inlineArray(CallInfo &callInfo)
callInfo.setImplicitlyUsedUnchecked();
MConstant *templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
MConstant *templateConst = MConstant::NewConstraintlessObject(alloc(), templateArray);
current->add(templateConst);
MNewArray *ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
templateObject->type()->initialHeap(constraints()),
templateArray->type()->initialHeap(constraints()),
allocating);
current->add(ins);
current->push(ins);
@ -730,7 +734,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
}
// Inline the call.
NativeObject *templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat);
JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat);
if (!templateObj || templateObj->type() != baseThisType)
return InliningStatus_NotInlined;
MOZ_ASSERT(templateObj->is<ArrayObject>());
@ -1611,7 +1615,7 @@ IonBuilder::inlineObjectCreate(CallInfo &callInfo)
if (callInfo.argc() != 1 || callInfo.constructing())
return InliningStatus_NotInlined;
NativeObject *templateObject = inspector->getTemplateObjectForNative(pc, obj_create);
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, obj_create);
if (!templateObject)
return InliningStatus_NotInlined;
@ -2613,5 +2617,37 @@ IonBuilder::inlineConstructSimdObject(CallInfo &callInfo, SimdTypeDescr *descr)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineSimdInt32x4BinaryArith(CallInfo &callInfo, JSNative native,
MSimdBinaryArith::Operation op)
{
if (callInfo.argc() != 2)
return InliningStatus_NotInlined;
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, native);
if (!templateObject)
return InliningStatus_NotInlined;
InlineTypedObject *inlineTypedObject = &templateObject->as<InlineTypedObject>();
MOZ_ASSERT(inlineTypedObject->typeDescr().as<SimdTypeDescr>().type() == js::Int32x4::type);
// If the type of any of the arguments is neither a SIMD type, an Object
// type, or a Value, then the applyTypes phase will add a fallible box &
// unbox sequence. This does not matter much as the binary arithmetic
// instruction is supposed to produce a TypeError once it is called.
MSimdBinaryArith *ins = MSimdBinaryArith::New(alloc(), callInfo.getArg(0), callInfo.getArg(1),
op, MIRType_Int32x4);
MSimdBox *obj = MSimdBox::New(alloc(), constraints(), ins, inlineTypedObject,
inlineTypedObject->type()->initialHeap(constraints()));
current->add(ins);
current->add(obj);
current->push(obj);
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
}
} // namespace jit
} // namespace js

View File

@ -1922,7 +1922,7 @@ class MSimdBinaryComp
class MSimdBinaryArith
: public MBinaryInstruction,
public NoTypePolicy::Data
public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
{
public:
enum Operation {
@ -1958,8 +1958,6 @@ class MSimdBinaryArith
{
MOZ_ASSERT_IF(type == MIRType_Int32x4, op == Add || op == Sub || op == Mul);
MOZ_ASSERT(IsSimdType(type));
MOZ_ASSERT(left->type() == right->type());
MOZ_ASSERT(left->type() == type);
setResultType(type);
setMovable();
if (op == Add || op == Mul || op == Min || op == Max)
@ -1968,10 +1966,18 @@ class MSimdBinaryArith
public:
INSTRUCTION_HEADER(SimdBinaryArith)
static MSimdBinaryArith *New(TempAllocator &alloc, MDefinition *left, MDefinition *right,
Operation op, MIRType t)
{
return new(alloc) MSimdBinaryArith(left, right, op, t);
}
static MSimdBinaryArith *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right,
Operation op, MIRType t)
{
return new(alloc) MSimdBinaryArith(left, right, op, t);
MOZ_ASSERT(left->type() == right->type());
MOZ_ASSERT(left->type() == t);
return New(alloc, left, right, op, t);
}
AliasSet getAliasSet() const MOZ_OVERRIDE {
@ -2984,6 +2990,33 @@ class MSimdBox
}
};
class MSimdUnbox
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
protected:
MSimdUnbox(MDefinition *op, MIRType type)
: MUnaryInstruction(op)
{
MOZ_ASSERT(IsSimdType(type));
setMovable();
setResultType(type);
}
public:
INSTRUCTION_HEADER(SimdUnbox)
ALLOW_CLONE(MSimdUnbox)
static MSimdUnbox *New(TempAllocator &alloc, MDefinition *op, MIRType type)
{
return new(alloc) MSimdUnbox(op, type);
}
AliasSet getAliasSet() const MOZ_OVERRIDE {
return AliasSet::None();
}
};
// Creates a new derived type object. At runtime, this is just a call
// to `BinaryBlock::createDerived()`. That is, the MIR itself does not
// compile to particularly optimized code. However, using a distinct

View File

@ -13,6 +13,7 @@ namespace jit {
#define MIR_OPCODE_LIST(_) \
_(Constant) \
_(SimdBox) \
_(SimdUnbox) \
_(SimdValueX4) \
_(SimdSplatX4) \
_(SimdConstant) \

View File

@ -1356,6 +1356,20 @@ MacroAssembler::assumeUnreachable(const char *output)
breakpoint();
}
template<typename T>
void
MacroAssembler::assertTestInt32(Condition cond, const T &value, const char *output)
{
#ifdef DEBUG
Label ok;
branchTestInt32(cond, value, &ok);
assumeUnreachable(output);
bind(&ok);
#endif
}
template void MacroAssembler::assertTestInt32(Condition, const Address &, const char *);
static void
Printf0_(const char *output) {
// Use stderr instead of stdout because this is only used for debug

View File

@ -976,6 +976,10 @@ class MacroAssembler : public MacroAssemblerSpecific
void link(JitCode *code);
void assumeUnreachable(const char *output);
template<typename T>
void assertTestInt32(Condition cond, const T &value, const char *output);
void printf(const char *output);
void printf(const char *output, Register value);

View File

@ -19,10 +19,38 @@
using namespace js;
using namespace js::jit;
// Encodings:
// [ptr] A fixed-size pointer.
// [vwu] A variable-width unsigned integer.
// [vws] A variable-width signed integer.
// [u8] An 8-bit unsigned integer.
// [u8'] An 8-bit unsigned integer which is potentially extended with packed
// data.
// [u8"] Packed data which is stored and packed in the previous [u8'].
// [vwu*] A list of variable-width unsigned integers.
// [pld] Payload of Recover Value Allocation:
// PAYLOAD_NONE:
// There is no payload.
//
// PAYLOAD_INDEX:
// [vwu] Index, such as the constant pool index.
//
// PAYLOAD_STACK_OFFSET:
// [vws] Stack offset based on the base of the Ion frame.
//
// PAYLOAD_GPR:
// [u8] Code of the general register.
//
// PAYLOAD_FPU:
// [u8] Code of the FPU register.
//
// PAYLOAD_PACKED_TAG:
// [u8"] Bits 5-7: JSValueType is encoded on the low bits of the Mode
// of the RValueAllocation.
//
// Snapshot header:
//
// [vwu] bits ((n+1)-31]: frame count
// bit n+1: resume after
// [vwu] bits ((n+1)-31]: recover instruction offset
// bits [0,n): bailout kind (n = SNAPSHOT_BAILOUTKIND_BITS)
//
// Snapshot body, repeated "frame count" times, from oldest frame to newest frame.
@ -92,35 +120,6 @@ using namespace js::jit;
// Value with statically known type, which payload is stored at an
// offset on the stack.
//
// Encodings:
// [ptr] A fixed-size pointer.
// [vwu] A variable-width unsigned integer.
// [vws] A variable-width signed integer.
// [u8] An 8-bit unsigned integer.
// [u8'] An 8-bit unsigned integer which is potentially extended with packed
// data.
// [u8"] Packed data which is stored and packed in the previous [u8'].
// [vwu*] A list of variable-width unsigned integers.
// [pld] Payload of Recover Value Allocation:
// PAYLOAD_NONE:
// There is no payload.
//
// PAYLOAD_INDEX:
// [vwu] Index, such as the constant pool index.
//
// PAYLOAD_STACK_OFFSET:
// [vws] Stack offset based on the base of the Ion frame.
//
// PAYLOAD_GPR:
// [u8] Code of the general register.
//
// PAYLOAD_FPU:
// [u8] Code of the FPU register.
//
// PAYLOAD_PACKED_TAG:
// [u8"] Bits 5-7: JSValueType is encoded on the low bits of the Mode
// of the RValueAllocation.
//
const RValueAllocation::Layout &
RValueAllocation::layoutFromMode(Mode mode)
@ -498,7 +497,7 @@ SnapshotReader::SnapshotReader(const uint8_t *snapshots, uint32_t offset,
// Details of snapshot header packing.
static const uint32_t SNAPSHOT_BAILOUTKIND_SHIFT = 0;
static const uint32_t SNAPSHOT_BAILOUTKIND_BITS = 5;
static const uint32_t SNAPSHOT_BAILOUTKIND_BITS = 6;
static const uint32_t SNAPSHOT_BAILOUTKIND_MASK = COMPUTE_MASK_(SNAPSHOT_BAILOUTKIND);
static const uint32_t SNAPSHOT_ROFFSET_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);

View File

@ -75,7 +75,7 @@ class StackSlotAllocator
StackSlotAllocator() : height_(0)
{ }
void freeSlot(LDefinition::Type type, uint32_t index) {
static uint32_t width(LDefinition::Type type) {
switch (type) {
#if JS_BITS_PER_WORD == 32
case LDefinition::GENERAL:
@ -83,7 +83,7 @@ class StackSlotAllocator
case LDefinition::SLOTS:
#endif
case LDefinition::INT32:
case LDefinition::FLOAT32: return freeSlot(index);
case LDefinition::FLOAT32: return 4;
#if JS_BITS_PER_WORD == 64
case LDefinition::GENERAL:
case LDefinition::OBJECT:
@ -96,39 +96,29 @@ class StackSlotAllocator
case LDefinition::TYPE:
case LDefinition::PAYLOAD:
#endif
case LDefinition::DOUBLE: return freeDoubleSlot(index);
case LDefinition::DOUBLE: return 8;
case LDefinition::FLOAT32X4:
case LDefinition::INT32X4: return freeQuadSlot(index);
case LDefinition::INT32X4: return 16;
}
MOZ_CRASH("Unknown slot type");
}
uint32_t allocateSlot(LDefinition::Type type) {
switch (type) {
#if JS_BITS_PER_WORD == 32
case LDefinition::GENERAL:
case LDefinition::OBJECT:
case LDefinition::SLOTS:
#endif
case LDefinition::INT32:
case LDefinition::FLOAT32: return allocateSlot();
#if JS_BITS_PER_WORD == 64
case LDefinition::GENERAL:
case LDefinition::OBJECT:
case LDefinition::SLOTS:
#endif
#ifdef JS_PUNBOX64
case LDefinition::BOX:
#endif
#ifdef JS_NUNBOX32
case LDefinition::TYPE:
case LDefinition::PAYLOAD:
#endif
case LDefinition::DOUBLE: return allocateDoubleSlot();
case LDefinition::FLOAT32X4:
case LDefinition::INT32X4: return allocateQuadSlot();
void freeSlot(LDefinition::Type type, uint32_t index) {
switch (width(type)) {
case 4: return freeSlot(index);
case 8: return freeDoubleSlot(index);
case 16: return freeQuadSlot(index);
}
MOZ_CRASH("Unknown slot type");
MOZ_CRASH("Unknown slot width");
}
uint32_t allocateSlot(LDefinition::Type type) {
switch (width(type)) {
case 4: return allocateSlot();
case 8: return allocateDoubleSlot();
case 16: return allocateQuadSlot();
}
MOZ_CRASH("Unknown slot width");
}
uint32_t stackHeight() const {

View File

@ -717,6 +717,29 @@ template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruc
template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
template <unsigned Op>
bool
SimdSameAsReturnedTypePolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
{
MIRType type = ins->type();
MOZ_ASSERT(IsSimdType(type));
MDefinition *in = ins->getOperand(Op);
if (in->type() == type)
return true;
MSimdUnbox *replace = MSimdUnbox::New(alloc, in, type);
ins->block()->insertBefore(ins, replace);
ins->replaceOperand(Op, replace);
return replace->typePolicy()->adjustInputs(alloc, replace);
}
template bool
SimdSameAsReturnedTypePolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
template bool
SimdSameAsReturnedTypePolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
bool
CallPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
{
@ -1042,6 +1065,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2> >) \
_(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >) \
_(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >) \
_(MixPolicy<StringPolicy<0>, IntPolicy<1> >) \
_(MixPolicy<StringPolicy<0>, StringPolicy<1> >) \
_(NoFloatPolicy<0>) \

View File

@ -317,6 +317,19 @@ class SimdScalarPolicy MOZ_FINAL : public TypePolicy
}
};
// SIMD value-type policy, use the returned type of the instruction to determine
// how to unbox its operand.
template <unsigned Op>
class SimdSameAsReturnedTypePolicy MOZ_FINAL : public TypePolicy
{
public:
EMPTY_DATA_;
static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE {
return staticAdjustInputs(alloc, ins);
}
};
template <unsigned Op>
class BoxPolicy MOZ_FINAL : public TypePolicy
{

View File

@ -777,7 +777,7 @@ DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok)
JitFrameLayout *prefix = frame->framePrefix();
EnsureExitFrame(prefix);
cx->mainThread().jitTop = (uint8_t *)prefix;
cx->runtime()->jitTop = (uint8_t *)prefix;
return false;
}

View File

@ -38,6 +38,7 @@ class MacroAssemblerARM : public Assembler
// address.
Register secondScratchReg_;
public:
// Higher level tag testing code.
Operand ToPayload(Operand base) {
return Operand(Register::FromCode(base.base()), base.disp());
@ -45,6 +46,8 @@ class MacroAssemblerARM : public Assembler
Address ToPayload(Address base) {
return ToPayload(Operand(base)).toAddress();
}
protected:
Operand ToType(Operand base) {
return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void *));
}

View File

@ -4226,7 +4226,7 @@ Simulator::execute()
int32_t rpc = resume_pc_;
if (MOZ_UNLIKELY(rpc != 0)) {
// AsmJS signal handler ran and we have to adjust the pc.
PerThreadData::innermostAsmJSActivation()->setResumePC((void *)get_pc());
JSRuntime::innermostAsmJSActivation()->setResumePC((void *)get_pc());
set_pc(rpc);
resume_pc_ = 0;
}
@ -4418,16 +4418,34 @@ Simulator::Current()
} // namespace js
js::jit::Simulator *
js::PerThreadData::simulator() const
JSRuntime::simulator() const
{
return simulator_;
}
js::jit::Simulator *
js::PerThreadData::simulator() const
{
return runtime_->simulator();
}
void
JSRuntime::setSimulator(js::jit::Simulator *sim)
{
simulator_ = sim;
simulatorStackLimit_ = sim->stackLimit();
}
void
js::PerThreadData::setSimulator(js::jit::Simulator *sim)
{
simulator_ = sim;
simulatorStackLimit_ = sim->stackLimit();
runtime_->setSimulator(sim);
}
uintptr_t *
JSRuntime::addressOfSimulatorStackLimit()
{
return &simulatorStackLimit_;
}
js::jit::SimulatorRuntime *
@ -4436,12 +4454,6 @@ js::PerThreadData::simulatorRuntime() const
return runtime_->simulatorRuntime();
}
uintptr_t *
js::PerThreadData::addressOfSimulatorStackLimit()
{
return &simulatorStackLimit_;
}
js::jit::SimulatorRuntime *
JSRuntime::simulatorRuntime() const
{

View File

@ -377,7 +377,7 @@ class Simulator
#define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror) \
JS_BEGIN_MACRO \
if (cx->mainThread().simulator()->overRecursedWithExtra(extra)) { \
if (cx->runtime()->simulator()->overRecursedWithExtra(extra)) { \
js_ReportOverRecursed(cx); \
onerror; \
} \

View File

@ -67,12 +67,13 @@ static_assert(1 << defaultShift == sizeof(jsval), "The defaultShift is wrong");
class MacroAssemblerMIPS : public Assembler
{
protected:
public:
// higher level tag testing code
Operand ToPayload(Operand base);
Address ToPayload(Address base) {
return ToPayload(Operand(base)).toAddress();
}
protected:
Operand ToType(Operand base);
Address ToType(Address base) {
return ToType(Operand(base)).toAddress();

View File

@ -3312,7 +3312,7 @@ Simulator::execute()
// Get the PC to simulate. Cannot use the accessor here as we need the
// raw PC value and not the one used as input to arithmetic instructions.
int program_counter = get_pc();
AsmJSActivation *activation = TlsPerThreadData.get()->asmJSActivationStack();
AsmJSActivation *activation = TlsPerThreadData.get()->runtimeFromMainThread()->asmJSActivationStack();
while (program_counter != end_sim_pc) {
if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) {
@ -3470,16 +3470,34 @@ Simulator::popAddress()
} // namespace js
js::jit::Simulator *
js::PerThreadData::simulator() const
JSRuntime::simulator() const
{
return simulator_;
}
js::jit::Simulator *
js::PerThreadData::simulator() const
{
return runtime_->simulator();
}
void
JSRuntime::setSimulator(js::jit::Simulator *sim)
{
simulator_ = sim;
simulatorStackLimit_ = sim->stackLimit();
}
void
js::PerThreadData::setSimulator(js::jit::Simulator *sim)
{
simulator_ = sim;
simulatorStackLimit_ = sim->stackLimit();
runtime_->setSimulator(sim);
}
uintptr_t *
JSRuntime::addressOfSimulatorStackLimit()
{
return &simulatorStackLimit_;
}
js::jit::SimulatorRuntime *
@ -3488,12 +3506,6 @@ js::PerThreadData::simulatorRuntime() const
return runtime_->simulatorRuntime();
}
uintptr_t *
js::PerThreadData::addressOfSimulatorStackLimit()
{
return &simulatorStackLimit_;
}
js::jit::SimulatorRuntime *
JSRuntime::simulatorRuntime() const
{

View File

@ -161,6 +161,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
/////////////////////////////////////////////////////////////////
// X86/X64-common interface.
/////////////////////////////////////////////////////////////////
Address ToPayload(Address value) {
return value;
}
void storeValue(ValueOperand val, Operand dest) {
movq(val.valueReg(), dest);
}

View File

@ -380,18 +380,47 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
// Do not erase the frame pointer in this function.
MacroAssembler masm(cx);
// Caller:
// [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- rsp
// '--- #r8 ---'
// ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
// Including |this|, there are (|nargs| + 1) arguments to copy.
MOZ_ASSERT(ArgumentsRectifierReg == r8);
// Load the number of |undefined|s to push into %rcx.
// Add |this|, in the counter of known arguments.
masm.addl(Imm32(1), r8);
// Load |nformals| into %rcx.
masm.loadPtr(Address(rsp, RectifierFrameLayout::offsetOfCalleeToken()), rax);
masm.mov(rax, rcx);
masm.andq(Imm32(uint32_t(CalleeTokenMask)), rcx);
masm.movzwl(Operand(rcx, JSFunction::offsetOfNargs()), rcx);
// Including |this|, there are (|nformals| + 1) arguments to push to the
// stack. Then we push a JitFrameLayout. We compute the padding expressed
// in the number of extra |undefined| values to push on the stack.
static_assert(sizeof(JitFrameLayout) % JitStackAlignment == 0,
"No need to consider the JitFrameLayout for aligning the stack");
static_assert(JitStackAlignment % sizeof(Value) == 0,
"Ensure that we can pad the stack by pushing extra UndefinedValue");
const uint32_t alignment = JitStackAlignment / sizeof(Value);
MOZ_ASSERT(IsPowerOfTwo(alignment));
masm.addl(Imm32(alignment - 1 /* for padding */ + 1 /* for |this| */), rcx);
masm.andl(Imm32(~(alignment - 1)), rcx);
// Load the number of |undefined|s to push into %rcx.
masm.subq(r8, rcx);
// Caller:
// [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- rsp <- r9
// '------ #r8 -------'
//
// Rectifier frame:
// [undef] [undef] [undef] [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]]
// '------- #rcx --------' '------ #r8 -------'
// Copy the number of actual arguments
masm.loadPtr(Address(rsp, RectifierFrameLayout::offsetOfNumActualArgs()), rdx);
@ -399,7 +428,7 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
masm.movq(rsp, r9); // Save %rsp.
// Push undefined.
// Push undefined. (including the padding)
{
Label undefLoopTop;
masm.bind(&undefLoopTop);
@ -410,11 +439,14 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
}
// Get the topmost argument.
BaseIndex b = BaseIndex(r9, r8, TimesEight, sizeof(RectifierFrameLayout));
static_assert(sizeof(Value) == 8, "TimesEight is used to skip arguments");
// | - sizeof(Value)| is used to put rcx such that we can read the last
// argument, and not the value which is after.
BaseIndex b = BaseIndex(r9, r8, TimesEight, sizeof(RectifierFrameLayout) - sizeof(Value));
masm.lea(Operand(b), rcx);
// Push arguments, |nargs| + 1 times (to include |this|).
masm.addl(Imm32(1), r8);
// Copy & Push arguments, |nargs| + 1 times (to include |this|).
{
Label copyLoopTop;
@ -425,6 +457,14 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
masm.j(Assembler::NonZero, &copyLoopTop);
}
// Caller:
// [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- r9
//
//
// Rectifier frame:
// [undef] [undef] [undef] [arg2] [arg1] [this] <- rsp [[argc] [callee] [descr] [raddr]]
//
// Construct descriptor.
masm.subq(rsp, r9);
masm.makeFrameDescriptor(r9, JitFrame_Rectifier);

View File

@ -370,6 +370,9 @@ JitCode *
JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
{
MacroAssembler masm(cx);
// Caller:
// [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- esp
// '-- #esi ---'
// ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
// Including |this|, there are (|nargs| + 1) arguments to copy.
@ -380,6 +383,22 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
masm.mov(eax, ecx);
masm.andl(Imm32(CalleeTokenMask), ecx);
masm.movzwl(Operand(ecx, JSFunction::offsetOfNargs()), ecx);
// The frame pointer and its padding are pushed on the stack.
// Including |this|, there are (|nformals| + 1) arguments to push to the
// stack. Then we push a JitFrameLayout. We compute the padding expressed
// in the number of extra |undefined| values to push on the stack.
static_assert(sizeof(JitFrameLayout) % JitStackAlignment == 0,
"No need to consider the JitFrameLayout for aligning the stack");
static_assert((sizeof(Value) + 2 * sizeof(void *)) % JitStackAlignment == 0,
"No need to consider |this| and the frame pointer and its padding for aligning the stack");
static_assert(JitStackAlignment % sizeof(Value) == 0,
"Ensure that we can pad the stack by pushing extra UndefinedValue");
const uint32_t alignment = JitStackAlignment / sizeof(Value);
MOZ_ASSERT(IsPowerOfTwo(alignment));
masm.addl(Imm32(alignment - 1 /* for padding */), ecx);
masm.andl(Imm32(~(alignment - 1)), ecx);
masm.subl(esi, ecx);
// Copy the number of actual arguments.
@ -393,6 +412,17 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
// BaselineJIT.cpp/InitFromBailout. Check for the |#if defined(JS_CODEGEN_X86)| portions.
masm.push(FramePointer);
masm.movl(esp, FramePointer); // Save %esp.
masm.push(FramePointer /* padding */);
// Caller:
// [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]]
// '-- #esi ---'
//
// Rectifier frame:
// [ebp'] <- ebp [padding] <- esp [undef] [undef] [arg2] [arg1] [this]
// '--- #ecx ----' '-- #esi ---'
//
// [[argc] [callee] [descr] [raddr]]
// Push undefined.
{

View File

@ -1732,7 +1732,7 @@ JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize, size_t trusted
SetNativeStackQuotaAndLimit(rt, StackForTrustedScript, trustedScriptStackSize);
SetNativeStackQuotaAndLimit(rt, StackForUntrustedScript, untrustedScriptStackSize);
rt->mainThread.initJitStackLimit();
rt->initJitStackLimit();
}
/************************************************************************/
@ -5894,7 +5894,7 @@ HideScriptedCaller(JSContext *cx)
// If there's no accessible activation on the stack, we'll return null from
// DescribeScriptedCaller anyway, so there's no need to annotate anything.
Activation *act = cx->runtime()->mainThread.activation();
Activation *act = cx->runtime()->activation();
if (!act)
return;
act->hideScriptedCaller();
@ -5903,7 +5903,7 @@ HideScriptedCaller(JSContext *cx)
JS_PUBLIC_API(void)
UnhideScriptedCaller(JSContext *cx)
{
Activation *act = cx->runtime()->mainThread.activation();
Activation *act = cx->runtime()->activation();
if (!act)
return;
act->unhideScriptedCaller();

View File

@ -1047,7 +1047,7 @@ JSContext::saveFrameChain()
if (!savedFrameChains_.append(SavedFrameChain(compartment(), enterCompartmentDepth_)))
return false;
if (Activation *act = mainThread().activation())
if (Activation *act = runtime()->activation())
act->saveFrameChain();
setCompartment(nullptr);
@ -1065,7 +1065,7 @@ JSContext::restoreFrameChain()
setCompartment(sfc.compartment);
enterCompartmentDepth_ = sfc.enterCompartmentCount;
if (Activation *act = mainThread().activation())
if (Activation *act = runtime()->activation())
act->restoreFrameChain();
}
@ -1190,7 +1190,7 @@ void *
ExclusiveContext::stackLimitAddressForJitCode(StackKind kind)
{
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
return runtime_->mainThread.addressOfSimulatorStackLimit();
return runtime_->addressOfSimulatorStackLimit();
#endif
return stackLimitAddress(kind);
}

View File

@ -241,6 +241,7 @@ class ExclusiveContext : public ContextFriendFields,
void *runtimeAddressOfInterruptUint32() { return runtime_->addressOfInterruptUint32(); }
void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; }
void *stackLimitAddressForJitCode(StackKind kind);
uintptr_t stackLimit(StackKind kind) { return runtime_->mainThread.nativeStackLimit[kind]; }
size_t gcSystemPageSize() { return gc::SystemPageSize(); }
bool canUseSignalHandlers() const { return runtime_->canUseSignalHandlers(); }
bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; }
@ -435,16 +436,16 @@ struct JSContext : public js::ExclusiveContext,
bool currentlyRunning() const;
bool currentlyRunningInInterpreter() const {
return mainThread().activation()->isInterpreter();
return runtime_->activation()->isInterpreter();
}
bool currentlyRunningInJit() const {
return mainThread().activation()->isJit();
return runtime_->activation()->isJit();
}
js::InterpreterFrame *interpreterFrame() const {
return mainThread().activation()->asInterpreter()->current();
return runtime_->activation()->asInterpreter()->current();
}
js::InterpreterRegs &interpreterRegs() const {
return mainThread().activation()->asInterpreter()->regs();
return runtime_->activation()->asInterpreter()->regs();
}
/*

View File

@ -448,7 +448,7 @@ JSContext::currentScript(jsbytecode **ppc,
if (ppc)
*ppc = nullptr;
js::Activation *act = mainThread().activation();
js::Activation *act = runtime()->activation();
while (act && (act->cx() != this || (act->isJit() && !act->asJit()->isActive())))
act = act->prev();

View File

@ -2285,6 +2285,7 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
allocationSiteTable = cx->new_<AllocationSiteTable>();
if (!allocationSiteTable || !allocationSiteTable->init()) {
js_delete(allocationSiteTable);
allocationSiteTable = nullptr;
return nullptr;
}
}
@ -3330,7 +3331,8 @@ TypeObject::clearNewScript(ExclusiveContext *cx)
newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);
} else {
// Threads with an ExclusiveContext are not allowed to run scripts.
MOZ_ASSERT(!cx->perThreadData->activation());
MOZ_ASSERT(!cx->perThreadData->runtimeIfOnOwnerThread() ||
!cx->perThreadData->runtimeIfOnOwnerThread()->activation());
}
js_delete(newScript);
@ -4611,7 +4613,9 @@ ConstraintTypeSet::sweep(Zone *zone, AutoClearTypeInferenceStateOnOOM &oom)
objectCount = 0;
for (unsigned i = 0; i < oldCapacity; i++) {
TypeObjectKey *object = oldArray[i];
if (object && !IsAboutToBeFinalized(&object)) {
if (!object)
continue;
if (!IsAboutToBeFinalized(&object)) {
TypeObjectKey **pentry =
HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
(zone->types.typeLifoAlloc, objectSet, objectCount, object);
@ -4624,16 +4628,28 @@ ConstraintTypeSet::sweep(Zone *zone, AutoClearTypeInferenceStateOnOOM &oom)
objectCount = 0;
break;
}
} else if (object->isTypeObject() && object->asTypeObject()->unknownProperties()) {
// Object sets containing objects with unknown properties might
// not be complete. Mark the type set as unknown, which it will
// be treated as during Ion compilation.
flags |= TYPE_FLAG_ANYOBJECT;
clearObjects();
objectCount = 0;
break;
}
}
setBaseObjectCount(objectCount);
} else if (objectCount == 1) {
TypeObjectKey *object = (TypeObjectKey *) objectSet;
if (IsAboutToBeFinalized(&object)) {
if (!IsAboutToBeFinalized(&object)) {
objectSet = reinterpret_cast<TypeObjectKey **>(object);
} else {
// As above, mark type sets containing objects with unknown
// properties as unknown.
if (object->isTypeObject() && object->asTypeObject()->unknownProperties())
flags |= TYPE_FLAG_ANYOBJECT;
objectSet = nullptr;
setBaseObjectCount(0);
} else {
objectSet = reinterpret_cast<TypeObjectKey **>(object);
}
}

View File

@ -454,7 +454,7 @@ struct PerThreadDataFriendFields
}
/* Limit pointer for checking native stack consumption. */
uintptr_t nativeStackLimit[StackKindCount];
uintptr_t nativeStackLimit[js::StackKindCount];
static const size_t RuntimeMainThreadOffset = offsetof(RuntimeDummy, mainThread);

View File

@ -4209,7 +4209,7 @@ EnableSingleStepProfiling(JSContext *cx, unsigned argc, Value *vp)
#if defined(JS_ARM_SIMULATOR)
CallArgs args = CallArgsFromVp(argc, vp);
jit::Simulator *sim = cx->runtime()->mainThread.simulator();
jit::Simulator *sim = cx->runtime()->simulator();
sim->enable_single_stepping(SingleStepCallback, cx->runtime());
args.rval().setUndefined();
@ -4226,7 +4226,7 @@ DisableSingleStepProfiling(JSContext *cx, unsigned argc, Value *vp)
#if defined(JS_ARM_SIMULATOR)
CallArgs args = CallArgsFromVp(argc, vp);
jit::Simulator *sim = cx->runtime()->mainThread.simulator();
jit::Simulator *sim = cx->runtime()->simulator();
sim->disable_single_stepping();
AutoValueVector elems(cx);

View File

@ -1084,6 +1084,42 @@ Debugger::receiveCompletionValue(Maybe<AutoCompartment> &ac, bool ok,
return newCompletionValue(cx, status, value, vp);
}
static bool
GetStatusProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSTrapStatus status,
JSTrapStatus *statusOut, MutableHandleValue vp, int *hits)
{
bool found;
if (!HasProperty(cx, obj, name, &found))
return false;
if (found) {
++*hits;
*statusOut = status;
if (!GetProperty(cx, obj, obj, name, vp))
return false;
}
return true;
}
static bool
ParseResumptionValueAsObject(JSContext *cx, HandleValue rv, JSTrapStatus *statusp,
MutableHandleValue vp)
{
int hits = 0;
if (rv.isObject()) {
RootedObject obj(cx, &rv.toObject());
if (!GetStatusProperty(cx, obj, cx->names().return_, JSTRAP_RETURN, statusp, vp, &hits))
return false;
if (!GetStatusProperty(cx, obj, cx->names().throw_, JSTRAP_THROW, statusp, vp, &hits))
return false;
}
if (hits != 1) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_RESUMPTION);
return false;
}
return true;
}
JSTrapStatus
Debugger::parseResumptionValue(Maybe<AutoCompartment> &ac, bool ok, const Value &rv, MutableHandleValue vp,
bool callHook)
@ -1100,35 +1136,16 @@ Debugger::parseResumptionValue(Maybe<AutoCompartment> &ac, bool ok, const Value
return JSTRAP_ERROR;
}
/* Check that rv is {return: val} or {throw: val}. */
JSContext *cx = ac->context()->asJSContext();
Rooted<JSObject*> obj(cx);
RootedShape shape(cx);
RootedId returnId(cx, NameToId(cx->names().return_));
RootedId throwId(cx, NameToId(cx->names().throw_));
bool okResumption = rv.isObject();
if (okResumption) {
obj = &rv.toObject();
okResumption = obj->is<PlainObject>();
}
if (okResumption) {
shape = obj->lastProperty();
okResumption = shape->previous() &&
!shape->previous()->previous() &&
(shape->propid() == returnId || shape->propid() == throwId) &&
shape->isDataDescriptor();
}
if (!okResumption) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_RESUMPTION);
JSTrapStatus status = JSTRAP_CONTINUE;
RootedValue v(cx);
RootedValue rvRoot(cx, rv);
if (!ParseResumptionValueAsObject(cx, rvRoot, &status, &v) ||
!unwrapDebuggeeValue(cx, &v))
{
return handleUncaughtException(ac, vp, callHook);
}
HandleNativeObject nobj = obj.as<NativeObject>();
RootedValue v(cx, vp.get());
if (!NativeGetExistingProperty(cx, obj, nobj, shape, &v) || !unwrapDebuggeeValue(cx, &v))
return handleUncaughtException(ac, &v, callHook);
ac.reset();
if (!cx->compartment()->wrap(cx, &v)) {
vp.setUndefined();
@ -1136,7 +1153,7 @@ Debugger::parseResumptionValue(Maybe<AutoCompartment> &ac, bool ok, const Value
}
vp.set(v);
return shape->propid() == returnId ? JSTRAP_RETURN : JSTRAP_THROW;
return status;
}
static bool

View File

@ -1518,22 +1518,38 @@ js::NativeDefineElement(ExclusiveContext *cx, HandleNativeObject obj, uint32_t i
return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs);
}
/*** [[Get]] *************************************************************************************/
static inline bool
CallGetter(JSContext* cx, HandleObject receiver, HandleShape shape, MutableHandleValue vp)
{
MOZ_ASSERT(!shape->hasDefaultGetter());
if (shape->hasGetterValue()) {
Value fval = shape->getterValue();
return InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp);
}
RootedId id(cx, shape->propid());
return CallJSPropertyOp(cx, shape->getterOp(), receiver, id, vp);
}
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE bool
NativeGetExistingPropertyInline(JSContext *cx,
typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
typename MaybeRooted<NativeObject*, allowGC>::HandleType pobj,
typename MaybeRooted<Shape*, allowGC>::HandleType shape,
typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
GetExistingProperty(JSContext *cx,
typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
typename MaybeRooted<Shape*, allowGC>::HandleType shape,
typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
{
if (shape->hasSlot()) {
vp.set(pobj->getSlot(shape->slot()));
vp.set(obj->getSlot(shape->slot()));
MOZ_ASSERT_IF(!vp.isMagic(JS_UNINITIALIZED_LEXICAL) &&
!pobj->hasSingletonType() &&
!pobj->template is<ScopeObject>() &&
!obj->hasSingletonType() &&
!obj->template is<ScopeObject>() &&
shape->hasDefaultGetter(),
js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), vp));
js::types::TypeHasProperty(cx, obj->type(), shape->propid(), vp));
} else {
vp.setUndefined();
}
@ -1559,40 +1575,41 @@ NativeGetExistingPropertyInline(JSContext *cx,
if (!allowGC)
return false;
if (!shape->get(cx,
if (!CallGetter(cx,
MaybeRooted<JSObject*, allowGC>::toHandle(receiver),
MaybeRooted<JSObject*, allowGC>::toHandle(obj),
MaybeRooted<JSObject*, allowGC>::toHandle(pobj),
MaybeRooted<Shape*, allowGC>::toHandle(shape),
MaybeRooted<Value, allowGC>::toMutableHandle(vp)))
{
return false;
}
/* Update slotful shapes according to the value produced by the getter. */
if (shape->hasSlot() && pobj->contains(cx, shape))
pobj->setSlot(shape->slot(), vp);
// Ancient nonstandard extension: via the JSAPI it's possible to create a
// data property that has both a slot and a getter. In that case, copy the
// value returned by the getter back into the slot.
if (shape->hasSlot() && obj->contains(cx, shape))
obj->setSlot(shape->slot(), vp);
return true;
}
bool
js::NativeGetExistingProperty(JSContext *cx, HandleObject obj, HandleNativeObject pobj,
js::NativeGetExistingProperty(JSContext *cx, HandleObject receiver, HandleNativeObject obj,
HandleShape shape, MutableHandleValue vp)
{
return NativeGetExistingPropertyInline<CanGC>(cx, obj, obj, pobj, shape, vp);
return GetExistingProperty<CanGC>(cx, receiver, obj, shape, vp);
}
/*
* Given pc pointing after a property accessing bytecode, return true if the
* access is "object-detecting" in the sense used by web scripts, e.g., when
* checking whether document.all is defined.
* access is "property-detecting" -- that is, if we shouldn't warn about it
* even if no such property is found and strict warnings are enabled.
*/
static bool
Detecting(JSContext *cx, JSScript *script, jsbytecode *pc)
{
MOZ_ASSERT(script->containsPC(pc));
/* General case: a branch or equality op follows the access. */
// General case: a branch or equality op follows the access.
JSOp op = JSOp(*pc);
if (js_CodeSpec[op].format & JOF_DETECTING)
return true;
@ -1600,10 +1617,7 @@ Detecting(JSContext *cx, JSScript *script, jsbytecode *pc)
jsbytecode *endpc = script->codeEnd();
if (op == JSOP_NULL) {
/*
* Special case #1: handle (document.all == null). Don't sweat
* about JS1.2's revision of the equality operators here.
*/
// Special case #1: don't warn about (obj.prop == null).
if (++pc < endpc) {
op = JSOp(*pc);
return op == JSOP_EQ || op == JSOP_NE;
@ -1612,11 +1626,7 @@ Detecting(JSContext *cx, JSScript *script, jsbytecode *pc)
}
if (op == JSOP_GETGNAME || op == JSOP_GETNAME) {
/*
* Special case #2: handle (document.all == undefined). Don't worry
* about a local variable named |undefined| shadowing the immutable
* global binding...because, really?
*/
// Special case #2: don't warn about (obj.prop == undefined).
JSAtom *atom = script->getAtom(GET_UINT32_INDEX(pc));
if (atom == cx->names().undefined &&
(pc += js_CodeSpec[op].length) < endpc) {
@ -1628,149 +1638,185 @@ Detecting(JSContext *cx, JSScript *script, jsbytecode *pc)
return false;
}
/*
* Finish getting the property `receiver[id]` after looking at every object on
* the prototype chain and not finding any such property.
*
* Per the spec, this should just set the result to `undefined` and call it a
* day. However:
*
* 1. We add support for the nonstandard JSClass::getProperty hook.
*
* 2. This function also runs when we're evaluating an expression that's an
* Identifier (that is, an unqualified name lookup), so we need to figure
* out if that's what's happening and throw a ReferenceError if so.
*
* 3. We also emit an optional warning for this. (It's not super useful on the
* web, as there are too many false positives, but anecdotally useful in
* Gecko code.)
*/
static bool
GetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleId id,
HandleObject receiver, MutableHandleValue vp)
{
vp.setUndefined();
// Non-standard extension: Call the getProperty hook. If it sets vp to a
// value other than undefined, we're done. If not, fall through to the
// warning/error checks below.
if (JSPropertyOp getProperty = obj->getClass()->getProperty) {
if (!CallJSPropertyOp(cx, getProperty, obj, id, vp))
return false;
if (!vp.isUndefined())
return true;
}
// If we are doing a name lookup, this is a ReferenceError.
jsbytecode *pc = nullptr;
RootedScript script(cx, cx->currentScript(&pc));
if (!pc)
return true;
JSOp op = (JSOp) *pc;
if (op == JSOP_GETXPROP) {
JSAutoByteString printable;
if (js_ValueToPrintable(cx, IdToValue(id), &printable))
js_ReportIsNotDefined(cx, printable.ptr());
return false;
}
// Give a strict warning if foo.bar is evaluated by a script for an object
// foo with no property named 'bar'.
//
// Don't warn if extra warnings not enabled or for random getprop
// operations.
if (!cx->compartment()->options().extraWarnings(cx) || (op != JSOP_GETPROP && op != JSOP_GETELEM))
return true;
// Don't warn repeatedly for the same script.
if (!script || script->warnedAboutUndefinedProp())
return true;
// Don't warn in self-hosted code (where the further presence of
// JS::RuntimeOptions::werror() would result in impossible-to-avoid
// errors to entirely-innocent client code).
if (script->selfHosted())
return true;
// We may just be checking if that object has an iterator.
if (JSID_IS_ATOM(id, cx->names().iteratorIntrinsic))
return true;
// Do not warn about tests like (obj[prop] == undefined).
pc += js_CodeSpec[op].length;
if (Detecting(cx, script, pc))
return true;
unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
script->setWarnedAboutUndefinedProp();
// Ok, bad undefined property reference: whine about it.
RootedValue val(cx, IdToValue(id));
return js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP, JSDVG_IGNORE_STACK, val,
js::NullPtr(), nullptr, nullptr);
}
/* The NoGC version of GetNonexistentProperty, present only to make types line up. */
bool
GetNonexistentProperty(JSContext *cx, NativeObject *obj, jsid id, JSObject *receiver,
FakeMutableHandle<Value> vp)
{
return false;
}
static inline bool
GeneralizedGetProperty(JSContext *cx, HandleObject obj, HandleId id, HandleObject receiver,
MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
return GetProperty(cx, obj, receiver, id, vp);
}
static inline bool
GeneralizedGetProperty(JSContext *cx, JSObject *obj, jsid id, JSObject *receiver,
FakeMutableHandle<Value> vp)
{
JS_CHECK_RECURSION_DONT_REPORT(cx, return false);
return GetPropertyNoGC(cx, obj, receiver, id, vp.address());
}
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE bool
GetPropertyHelperInline(JSContext *cx,
NativeGetPropertyInline(JSContext *cx,
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
typename MaybeRooted<jsid, allowGC>::HandleType id,
typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
{
/* This call site is hot -- use the always-inlined variant of LookupNativeProperty(). */
typename MaybeRooted<JSObject*, allowGC>::RootType obj2(cx);
typename MaybeRooted<NativeObject*, allowGC>::RootType pobj(cx, obj);
typename MaybeRooted<Shape*, allowGC>::RootType shape(cx);
if (!LookupPropertyInline<allowGC>(cx, obj, id, &obj2, &shape))
return false;
if (!shape) {
if (!allowGC)
// This loop isn't explicit in the spec algorithm. See the comment on step
// 4.d below.
for (;;) {
// Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
bool done;
if (!LookupOwnPropertyInline<allowGC>(cx, pobj, id, &shape, &done))
return false;
vp.setUndefined();
if (JSPropertyOp getProperty = obj->getClass()->getProperty) {
if (!CallJSPropertyOp(cx, getProperty,
MaybeRooted<JSObject*, allowGC>::toHandle(obj),
MaybeRooted<jsid, allowGC>::toHandle(id),
MaybeRooted<Value, allowGC>::toMutableHandle(vp)))
{
return false;
if (shape) {
// Steps 5-8. Special case for dense elements because
// GetExistingProperty doesn't support those.
if (IsImplicitDenseOrTypedArrayElement(shape)) {
vp.set(pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
return true;
}
return GetExistingProperty<allowGC>(cx, receiver, pobj, shape, vp);
}
/*
* Give a strict warning if foo.bar is evaluated by a script for an
* object foo with no property named 'bar'.
*/
if (vp.isUndefined()) {
jsbytecode *pc = nullptr;
RootedScript script(cx, cx->currentScript(&pc));
if (!pc)
return true;
JSOp op = (JSOp) *pc;
// Steps 4.a-b. The check for 'done' on this next line is tricky.
// done can be true in exactly these unlikely-sounding cases:
// - We're looking up an element, and pobj is a TypedArray that
// doesn't have that many elements.
// - We're being called from a resolve hook to assign to the property
// being resolved.
// What they all have in common is we do not want to keep walking
// the prototype chain.
RootedObject proto(cx, done ? nullptr : pobj->getProto());
if (op == JSOP_GETXPROP) {
/* Undefined property during a name lookup, report an error. */
JSAutoByteString printable;
if (js_ValueToPrintable(cx, IdToValue(id), &printable))
js_ReportIsNotDefined(cx, printable.ptr());
return false;
}
// Step 4.c. The spec algorithm simply returns undefined if proto is
// null, but see the comment on GetNonexistentProperty.
if (!proto)
return GetNonexistentProperty(cx, obj, id, receiver, vp);
/* Don't warn if extra warnings not enabled or for random getprop operations. */
if (!cx->compartment()->options().extraWarnings(cx) || (op != JSOP_GETPROP && op != JSOP_GETELEM))
return true;
// Step 4.d. If the prototype is also native, this step is a
// recursive tail call, and we don't need to go through all the
// plumbing of JSObject::getGeneric; the top of the loop is where
// we're going to end up anyway. But if pobj is non-native,
// that optimization would be incorrect.
if (!proto->isNative())
return GeneralizedGetProperty(cx, proto, id, receiver, vp);
/* Don't warn repeatedly for the same script. */
if (!script || script->warnedAboutUndefinedProp())
return true;
/*
* Don't warn in self-hosted code (where the further presence of
* JS::RuntimeOptions::werror() would result in impossible-to-avoid
* errors to entirely-innocent client code).
*/
if (script->selfHosted())
return true;
/* We may just be checking if that object has an iterator. */
if (JSID_IS_ATOM(id, cx->names().iteratorIntrinsic))
return true;
/* Do not warn about tests like (obj[prop] == undefined). */
pc += js_CodeSpec[op].length;
if (Detecting(cx, script, pc))
return true;
unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
script->setWarnedAboutUndefinedProp();
/* Ok, bad undefined property reference: whine about it. */
RootedValue val(cx, IdToValue(id));
if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP,
JSDVG_IGNORE_STACK, val, js::NullPtr(),
nullptr, nullptr))
{
return false;
}
}
return true;
pobj = &proto->as<NativeObject>();
}
if (!obj2->isNative()) {
if (!allowGC)
return false;
HandleObject obj2Handle = MaybeRooted<JSObject*, allowGC>::toHandle(obj2);
HandleObject receiverHandle = MaybeRooted<JSObject*, allowGC>::toHandle(receiver);
HandleId idHandle = MaybeRooted<jsid, allowGC>::toHandle(id);
MutableHandleValue vpHandle = MaybeRooted<Value, allowGC>::toMutableHandle(vp);
return obj2->template is<ProxyObject>()
? Proxy::get(cx, obj2Handle, receiverHandle, idHandle, vpHandle)
: GetProperty(cx, obj2Handle, obj2Handle, idHandle, vpHandle);
}
typename MaybeRooted<NativeObject*, allowGC>::HandleType nobj2 =
MaybeRooted<JSObject*, allowGC>::template downcastHandle<NativeObject>(obj2);
if (IsImplicitDenseOrTypedArrayElement(shape)) {
vp.set(nobj2->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
return true;
}
// This call site is hot -- use the always-inlined variant of
// NativeGetExistingProperty().
if (!NativeGetExistingPropertyInline<allowGC>(cx, obj, receiver, nobj2, shape, vp))
return false;
return true;
}
bool
js::NativeGetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
MutableHandleValue vp)
{
/* This call site is hot -- use the always-inlined variant of GetPropertyHelper(). */
return GetPropertyHelperInline<CanGC>(cx, obj, receiver, id, vp);
return NativeGetPropertyInline<CanGC>(cx, obj, receiver, id, vp);
}
bool
js::NativeGetPropertyNoGC(JSContext *cx, NativeObject *obj, JSObject *receiver, jsid id, Value *vp)
{
AutoAssertNoException nogc(cx);
return GetPropertyHelperInline<NoGC>(cx, obj, receiver, id, vp);
AutoAssertNoException noexc(cx);
return NativeGetPropertyInline<NoGC>(cx, obj, receiver, id, vp);
}
bool
js::NativeGetElement(JSContext *cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp)
{
RootedId id(cx);
if (!IndexToId(cx, index, &id))
return false;
/* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */
return GetPropertyHelperInline<CanGC>(cx, obj, receiver, id, vp);
}
/*** [[Set]] *************************************************************************************/
static bool
MaybeReportUndeclaredVarAssignment(JSContext *cx, JSString *propname)
@ -1796,9 +1842,6 @@ MaybeReportUndeclaredVarAssignment(JSContext *cx, JSString *propname)
JSMSG_UNDECLARED_VAR, bytes.ptr());
}
/*** [[Set]] *************************************************************************************/
/*
* When a [[Set]] operation finds no existing property with the given id
* or finds a writable data property on the prototype chain, we end up here.
@ -2069,7 +2112,8 @@ js::NativeSetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiv
RootedNativeObject pobj(cx, obj);
// This loop isn't explicit in the spec algorithm. See the comment on step
// 4.c.i below.
// 4.c.i below. (There's a very similar loop in the NativeGetProperty
// implementation, but unfortunately not similar enough to common up.)
for (;;) {
// Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
bool done;
@ -2128,6 +2172,9 @@ js::NativeSetElement(JSContext *cx, HandleNativeObject obj, HandleObject receive
return NativeSetProperty(cx, obj, receiver, id, Qualified, vp, strict);
}
/* * */
bool
js::NativeSetPropertyAttributes(JSContext *cx, HandleNativeObject obj, HandleId id,
unsigned *attrsp)

View File

@ -1322,8 +1322,15 @@ extern bool
NativeLookupElement(JSContext *cx, HandleNativeObject obj, uint32_t index,
MutableHandleObject objp, MutableHandleShape propp);
/*
* Get a property from `receiver`, after having already done a lookup and found
* the property on a native object `obj`.
*
* `shape` must not be null and must not be an implicit dense property. It must
* be present in obj's shape chain.
*/
extern bool
NativeGetExistingProperty(JSContext *cx, HandleObject obj, HandleNativeObject pobj,
NativeGetExistingProperty(JSContext *cx, HandleObject receiver, HandleNativeObject obj,
HandleShape shape, MutableHandle<Value> vp);
extern bool

View File

@ -73,21 +73,10 @@ const JSSecurityCallbacks js::NullSecurityCallbacks = { };
PerThreadData::PerThreadData(JSRuntime *runtime)
: PerThreadDataFriendFields(),
runtime_(runtime),
jitTop(nullptr),
jitJSContext(nullptr),
jitActivation(nullptr),
jitStackLimit_(0xbad),
#ifdef JS_TRACE_LOGGING
traceLogger(nullptr),
#endif
activation_(nullptr),
profilingActivation_(nullptr),
asmJSActivationStack_(nullptr),
autoFlushICache_(nullptr),
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
simulator_(nullptr),
simulatorStackLimit_(0),
#endif
dtoaState(nullptr),
suppressGC(0),
#ifdef DEBUG
@ -100,10 +89,6 @@ PerThreadData::~PerThreadData()
{
if (dtoaState)
js_DestroyDtoaState(dtoaState);
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
js_delete(simulator_);
#endif
}
bool
@ -113,9 +98,6 @@ PerThreadData::init()
if (!dtoaState)
return false;
if (!regexpStack.init())
return false;
return true;
}
@ -132,6 +114,13 @@ ReturnZeroSize(const void *p)
JSRuntime::JSRuntime(JSRuntime *parentRuntime)
: mainThread(this),
jitTop(nullptr),
jitJSContext(nullptr),
jitActivation(nullptr),
jitStackLimit_(0xbad),
activation_(nullptr),
profilingActivation_(nullptr),
asmJSActivationStack_(nullptr),
parentRuntime(parentRuntime),
interrupt_(false),
telemetryCallback(nullptr),
@ -168,6 +157,8 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
gc(thisFromCtor()),
gcInitialized(false),
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
simulator_(nullptr),
simulatorStackLimit_(0),
simulatorRuntime_(nullptr),
#endif
scriptAndCountsVector(nullptr),
@ -274,6 +265,9 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
if (!mainThread.init())
return false;
if (!regexpStack.init())
return false;
js::TlsPerThreadData.set(&mainThread);
if (CanUseExtraThreads())
@ -442,6 +436,7 @@ JSRuntime::~JSRuntime()
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
js::jit::DestroySimulatorRuntime(simulatorRuntime_);
js_delete(simulator_);
#endif
DebugOnly<size_t> oldCount = liveRuntimesCount--;
@ -594,7 +589,7 @@ InvokeInterruptCallback(JSContext *cx)
}
void
PerThreadData::resetJitStackLimit()
JSRuntime::resetJitStackLimit()
{
// Note that, for now, we use the untrusted limit for ion. This is fine,
// because it's the most conservative limit, and if we hit it, we'll bail
@ -602,12 +597,12 @@ PerThreadData::resetJitStackLimit()
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
jitStackLimit_ = jit::Simulator::StackLimit();
#else
jitStackLimit_ = nativeStackLimit[StackForUntrustedScript];
jitStackLimit_ = mainThread.nativeStackLimit[StackForUntrustedScript];
#endif
}
void
PerThreadData::initJitStackLimit()
JSRuntime::initJitStackLimit()
{
resetJitStackLimit();
}
@ -616,7 +611,7 @@ void
JSRuntime::requestInterrupt(InterruptMode mode)
{
interrupt_ = true;
mainThread.jitStackLimit_ = UINTPTR_MAX;
jitStackLimit_ = UINTPTR_MAX;
if (mode == JSRuntime::RequestInterruptUrgent)
InterruptRunningJitCode(this);
@ -626,9 +621,9 @@ bool
JSRuntime::handleInterrupt(JSContext *cx)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
if (interrupt_ || mainThread.jitStackLimit_ == UINTPTR_MAX) {
if (interrupt_ || jitStackLimit_ == UINTPTR_MAX) {
interrupt_ = false;
mainThread.resetJitStackLimit();
resetJitStackLimit();
return InvokeInterruptCallback(cx);
}
return true;

View File

@ -481,6 +481,11 @@ void DisableExtraThreads();
*/
class PerThreadData : public PerThreadDataFriendFields
{
#ifdef DEBUG
// Grant access to runtime_.
friend void js::AssertCurrentThreadCanLock(RuntimeLock which);
#endif
/*
* Backpointer to the full shared JSRuntime* with which this
* thread is associated. This is private because accessing the
@ -507,112 +512,14 @@ class PerThreadData : public PerThreadDataFriendFields
js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
#endif
/*
* If Baseline or Ion code is on the stack, and has called into C++, this
* will be aligned to an exit frame.
*/
uint8_t *jitTop;
/*
* The current JSContext when entering JIT code. This field may only be used
* from JIT code and C++ directly called by JIT code (otherwise it may refer
* to the wrong JSContext).
*/
JSContext *jitJSContext;
/*
* Points to the most recent JitActivation pushed on the thread.
* See JitActivation constructor in vm/Stack.cpp
*/
js::jit::JitActivation *jitActivation;
/* See comment for JSRuntime::interrupt_. */
private:
mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit_;
void resetJitStackLimit();
friend struct ::JSRuntime;
public:
void initJitStackLimit();
uintptr_t jitStackLimit() const { return jitStackLimit_; }
// For read-only JIT use:
void *addressOfJitStackLimit() { return &jitStackLimit_; }
static size_t offsetOfJitStackLimit() { return offsetof(PerThreadData, jitStackLimit_); }
// Information about the heap allocated backtrack stack used by RegExp JIT code.
irregexp::RegExpStack regexpStack;
#ifdef JS_TRACE_LOGGING
TraceLoggerThread *traceLogger;
#endif
private:
friend class js::Activation;
friend class js::ActivationIterator;
friend class js::jit::JitActivation;
friend class js::AsmJSActivation;
friend class js::jit::CompileRuntime;
#ifdef DEBUG
friend void js::AssertCurrentThreadCanLock(RuntimeLock which);
#endif
/*
* Points to the most recent activation running on the thread.
* See Activation comment in vm/Stack.h.
*/
js::Activation *activation_;
/*
* Points to the most recent profiling activation running on the
* thread.
*/
js::Activation * volatile profilingActivation_;
/* See AsmJSActivation comment. */
js::AsmJSActivation * volatile asmJSActivationStack_;
/* Pointer to the current AutoFlushICache. */
js::jit::AutoFlushICache *autoFlushICache_;
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
js::jit::Simulator *simulator_;
uintptr_t simulatorStackLimit_;
#endif
public:
js::Activation *const *addressOfActivation() const {
return &activation_;
}
static unsigned offsetOfAsmJSActivationStackReadOnly() {
return offsetof(PerThreadData, asmJSActivationStack_);
}
static unsigned offsetOfActivation() {
return offsetof(PerThreadData, activation_);
}
js::Activation *profilingActivation() const {
return profilingActivation_;
}
void *addressOfProfilingActivation() {
return (void*) &profilingActivation_;
}
static unsigned offsetOfProfilingActivation() {
return offsetof(PerThreadData, profilingActivation_);
}
js::AsmJSActivation *asmJSActivationStack() const {
return asmJSActivationStack_;
}
static js::AsmJSActivation *innermostAsmJSActivation() {
PerThreadData *ptd = TlsPerThreadData.get();
return ptd ? ptd->asmJSActivationStack_ : nullptr;
}
js::Activation *activation() const {
return activation_;
}
/* State used by jsdtoa.cpp. */
DtoaState *dtoaState;
@ -659,21 +566,10 @@ class PerThreadData : public PerThreadDataFriendFields
{
MOZ_ASSERT(!pt->runtime_);
pt->runtime_ = rt;
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
// The simulator has a pointer to its SimulatorRuntime, but helper threads
// don't have a simulator as they don't run JIT code so this pointer need not
// be updated. All the paths that the helper threads use access the
// SimulatorRuntime via the PerThreadData.
MOZ_ASSERT(!pt->simulator_);
#endif
}
~AutoEnterRuntime() {
pt->runtime_ = nullptr;
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
// Check that helper threads have not run JIT code and/or added a simulator.
MOZ_ASSERT(!pt->simulator_);
#endif
}
};
@ -684,7 +580,6 @@ class PerThreadData : public PerThreadDataFriendFields
js::jit::Simulator *simulator() const;
void setSimulator(js::jit::Simulator *sim);
js::jit::SimulatorRuntime *simulatorRuntime() const;
uintptr_t *addressOfSimulatorStackLimit();
#endif
};
@ -707,6 +602,97 @@ struct JSRuntime : public JS::shadow::Runtime,
*/
js::PerThreadData mainThread;
/*
* If Baseline or Ion code is on the stack, and has called into C++, this
* will be aligned to an exit frame.
*/
uint8_t *jitTop;
/*
* The current JSContext when entering JIT code. This field may only be used
* from JIT code and C++ directly called by JIT code (otherwise it may refer
* to the wrong JSContext).
*/
JSContext *jitJSContext;
/*
* Points to the most recent JitActivation pushed on the thread.
* See JitActivation constructor in vm/Stack.cpp
*/
js::jit::JitActivation *jitActivation;
/* See comment for JSRuntime::interrupt_. */
private:
mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit_;
void resetJitStackLimit();
public:
void initJitStackLimit();
uintptr_t jitStackLimit() const { return jitStackLimit_; }
// For read-only JIT use:
void *addressOfJitStackLimit() { return &jitStackLimit_; }
static size_t offsetOfJitStackLimit() { return offsetof(JSRuntime, jitStackLimit_); }
// Information about the heap allocated backtrack stack used by RegExp JIT code.
js::irregexp::RegExpStack regexpStack;
private:
friend class js::Activation;
friend class js::ActivationIterator;
friend class js::jit::JitActivation;
friend class js::AsmJSActivation;
friend class js::jit::CompileRuntime;
#ifdef DEBUG
friend void js::AssertCurrentThreadCanLock(js::RuntimeLock which);
#endif
/*
* Points to the most recent activation running on the thread.
* See Activation comment in vm/Stack.h.
*/
js::Activation *activation_;
/*
* Points to the most recent profiling activation running on the
* thread.
*/
js::Activation * volatile profilingActivation_;
/* See AsmJSActivation comment. */
js::AsmJSActivation * volatile asmJSActivationStack_;
public:
js::Activation *const *addressOfActivation() const {
return &activation_;
}
static unsigned offsetOfActivation() {
return offsetof(JSRuntime, activation_);
}
js::Activation *profilingActivation() const {
return profilingActivation_;
}
void *addressOfProfilingActivation() {
return (void*) &profilingActivation_;
}
static unsigned offsetOfProfilingActivation() {
return offsetof(JSRuntime, profilingActivation_);
}
js::AsmJSActivation *asmJSActivationStack() const {
return asmJSActivationStack_;
}
static js::AsmJSActivation *innermostAsmJSActivation() {
js::PerThreadData *ptd = js::TlsPerThreadData.get();
return ptd ? ptd->runtimeFromMainThread()->asmJSActivationStack_ : nullptr;
}
js::Activation *activation() const {
return activation_;
}
/*
* If non-null, another runtime guaranteed to outlive this one and whose
* permanent data may be used by this one where possible.
@ -988,6 +974,8 @@ struct JSRuntime : public JS::shadow::Runtime,
}
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
js::jit::Simulator *simulator_;
uintptr_t simulatorStackLimit_;
js::jit::SimulatorRuntime *simulatorRuntime_;
#endif
@ -997,6 +985,9 @@ struct JSRuntime : public JS::shadow::Runtime,
}
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
js::jit::Simulator *simulator() const;
void setSimulator(js::jit::Simulator *sim);
uintptr_t *addressOfSimulatorStackLimit();
js::jit::SimulatorRuntime *simulatorRuntime() const;
void setSimulatorRuntime(js::jit::SimulatorRuntime *srt);
#endif
@ -1438,7 +1429,7 @@ namespace js {
static inline JSContext *
GetJSContextFromJitCode()
{
JSContext *cx = TlsPerThreadData.get()->jitJSContext;
JSContext *cx = js::TlsPerThreadData.get()->runtimeFromMainThread()->jitJSContext;
MOZ_ASSERT(cx);
return cx;
}

View File

@ -99,9 +99,9 @@ SPSProfiler::enable(bool enabled)
/* Update lastProfilingFrame to point to the top-most JS jit-frame currently on
* stack.
*/
if (rt->mainThread.jitActivation) {
void *lastProfilingFrame = GetTopProfilingJitFrame(rt->mainThread.jitTop);
rt->mainThread.jitActivation->setLastProfilingFrame(lastProfilingFrame);
if (rt->jitActivation) {
void *lastProfilingFrame = GetTopProfilingJitFrame(rt->jitTop);
rt->jitActivation->setLastProfilingFrame(lastProfilingFrame);
}
}

View File

@ -33,21 +33,6 @@ StackBaseShape::StackBaseShape(ExclusiveContext *cx, const Class *clasp,
compartment(cx->compartment_)
{}
inline bool
Shape::get(JSContext* cx, HandleObject receiver, JSObject* obj, JSObject *pobj,
MutableHandleValue vp)
{
MOZ_ASSERT(!hasDefaultGetter());
if (hasGetterValue()) {
Value fval = getterValue();
return InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp);
}
RootedId id(cx, propid());
return CallJSPropertyOp(cx, getterOp(), receiver, id, vp);
}
inline Shape *
Shape::search(ExclusiveContext *cx, jsid id)
{

View File

@ -917,7 +917,6 @@ class Shape : public gc::TenuredCell
setter() == rawSetter;
}
bool get(JSContext* cx, HandleObject receiver, JSObject *obj, JSObject *pobj, MutableHandleValue vp);
bool set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, MutableHandleValue vp);
BaseShape *base() const { return base_.get(); }

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