mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:34:03 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1170717 - Move heapState check up to readBarrier; r=jonco (b9c4df5ea) - Bug 1163908 - Export GL draw data to layerscope for drawing heat-map view. r=:djg (cf078d4fd) - Bug 1161372 - Add EventRegions on LayerScope. r=dglastonbury (49fc29e8a) - Files as of Bug 1138721 - Application reputation should check mac file extensions. r=mmc (4b76de8d8) - Bug 1024774 - Part 0: Upgrade the protobuf library. r=mmc,glandium (c98c08fbd) - Bug 1149397 - JS::ubi::Node::edges should return a mozilla::UniquePtr; r=jimb (32f755867) - Bug 1110039 - Part 1 - Add nsLayoutUtils::ClampRectToScrollFrames. r=roc (a8812c287) - Bug 1110039 - Part 2.1 - Add logger facility. r=roc (1a400bb1f) - Bug 1110039 - Part 2.2 - Add AccessibleCaret. r=roc (d8c2c759f) - Bug 1110039 - Part 2.3 - Add AccessibleCaretManager. r=roc (ba8ad6424) - Bug 1110039 - Part 2.4 - Add AccessibleCaretEventHub. r=roc (db4ef1fe6) - Bug 1110039 - Part 2.5 - Add all files to build system. r=roc (bee54dc43) - fix nsRefPtr includes - but build still broken (423d9f32d) - Bug 1110039 - Part 3 - Add gtest for AccessibleCaretEventHub. r=roc (cdf0df240) - Bug 1110039 - Part 4 - Hook new classes into the system. r=roc (438a4df68) - Bug 1109183 - Fix imports of the marionette client and remove spurious entry from sys.path provided by mach. r=ahal (86b814562) - Bug 1110039 - Part 5 - Reuse marionette tests for AccessibleCaret. r=roc (d5cd35016) - Bug 1110039 followup: Add 'override' keyword to Name() decl in Access# (cd0d9b0f6) - Bug 1140994 - Notify gaia to hide selection bubble when scrolling without APZ. r=roc (ca15626fa) - Bug 1143665 - Remove the ambiguous scroll position being passed around in scroll started/stop notifications. r=roc,ehsan (ce8f1d2a9) - Bug 1140238 - Part 1: Add a test to drag first caret over non-selectable. r=automatedtester (4080723fe) - Bug 1140238 - Part 2: Adjust ranges after changing selection direction. r=mats (add1f155d) - Bug 1140238 - Part 3: Clear maintain selection when dragging caret. r=mats (0aba36f24) - Bug 1024774 - Part 2: Implement a google::protobuf::ZeroCopyOutputStream wrapper around nsIOutputStream; r=jimb (30c6272d2) - Bug 1024774 - Part 3: Serialize heap snapshots. r=jimb (9d0c8f6ec) - Bug 1024774 - Part 1: Add the ChromeUtils WebIDL interface. r=bholley (8e81e8344) - Bug 1024774 - Part 4: Add an xpcshell test for saving heap snapshots. r=jimb (6e0a07069) - Bug 1024774 - Part 5: Add GTests for core dump serialization. r=jimb (79315c540) - clean up spurious char (9a1f9bc18) - Bug 1121528 - Avoid the inspector going blank when quickly navigating; r=bgrins (f4cff269f) - Bug 1155168 - Always use the same actor pool. r=ochameau (3e6cc5504) - Bug 1137527 - Part 1: Make the memory actor emit events for garbage collection. r=jryans (6dcdb18f8) - Bug 1137527 - Part 2: Add a test for GC MemoryActor events. r=jryans (df2bcf120) - Bug 1024774 - Part 6: Add a mochitest-chrome sanity check test. r=bholley (4b5bffe79) - Bug 1024774 - Part 7: Add HeapSnapshot WebIDL interface; r=bholley (7b5ae703a) - Bug 1024774 - Part 8: Add JS::ubi::Node::isLive; r=jimb (42a965f56) - Bug 1024774 - Part 9: Deserialize heap snapshots; r=jimb (fb3edfbc0) - Bug 1024774 - Part 10: Add an xpcshell test for reading heap snapshots. r=jimb (09c3390a1) - Bug 1024774 - Part 11: Implement a JS::ubi::Node specialization for DeserializedNode; r=jimb (d73362efe) - Bug 1024774 - Part 12: Add a GTest for the JS::ubi::Node specialization for DeserializedNode; r=jimb (4415acb73) - Bug 1024774 - Part 13: Change to new SpiderMonkey style from bug 1144366; r=me (15c4bcf87) - Bug 1024774 - Part 14: Ignore protobuf indirect calls in the GC hazard analysis; r=sfink (c5b141c59) - Bug 1024774 - Followup: Don't redefine the Debugger property in xpcshell tests; r=jorendorff (dc4f1f109) - Bug 1169791 - Strongly type NoteJSRoot; r=mccr8 (ba722a44f) - Bug 1169791 - Strongly type MergeZone; r=mccr8 (a118cf612) - Bug 1169791 - Strongly type GetTenuredGCThingZone; r=jonco, r=mccr8 (a4da82aea) - Bug 1171780 - We no longer need to cast out of barrieried types in GC; r=jonco (be83218fa) - Bug 1144361: Re-enable JIT code randomization on Win64. r=jandem (6c88b4312) - pointer style (458344bcd) - Bug 1156914 - Fix the MacroAssembler::pushValue(const Address&) footgun on 32 bit platforms. (r=jandem) (52d5c351d) - Bug 1156030 - Remove some obsolete static assertion macros from the tree; r=Waldo (84d8f3fea) - pointer style (ac3c92ce1) - Bug 1151323 - Handle loading unboxed int32 properties into floating point registers, r=jandem. (790920f3d) - Bug 1023297 - Use explicit constructors for ARM-specific classes. r=jandem (f7f12cd76) - Bug 1164229 - Rename ARM SetCond_ to SBit. r=efaust (c55e1d535) - Bug 977805 - Add an option to mark JIT pages as non-writable. r=luke bug 977805 - add missing #include. r=jandem (384abd6ad) - Bug 1173992 - Add ARM64 build support. r=glandium (540a7c784) - Bug 1170750 - Replace %f by %.16g in js/src. r=jandem (48f808c73) - Bug 1170750 - Use mfbt snprintf_literal instead of sprintf. r=jandem (3b2016484) - Bug 1170750 - jsprf.cpp: Sort headers properly. r=me (0956cd3a5) - Bug 923717 - Use structured control flow when testing for the forceInlineCaches option, r=nbp. (fc1dcef6e) - Bug 1158044 - Remove unused TypeWrapper class and untemplatize/cleanup some code. r=bhackett (a4d5de646) - Bug 1169355 - Remove unnecessary assertion, r=jandem. (f55c99552) - Bug 1162986 - Allow objects to be turned into singletons dynamically, r=jandem. (9c683e420) - Bug 1169731 - [[Call]] on a class constructor should throw. (r=jandem) (470895e3f) and fix for shared-js in UbiNode.h
This commit is contained in:
@@ -50,7 +50,6 @@ SEARCH_PATHS = [
|
||||
'testing/web-platform',
|
||||
'testing/web-platform/harness',
|
||||
'testing/marionette/client',
|
||||
'testing/marionette/client/marionette',
|
||||
'testing/marionette/transport',
|
||||
'testing/marionette/driver',
|
||||
'testing/mozbase/mozcrash',
|
||||
|
||||
@@ -2977,6 +2977,7 @@ then
|
||||
esac
|
||||
LDFLAGS="${_PTHREAD_LDFLAGS} ${LDFLAGS}"
|
||||
AC_SUBST(MOZ_USE_PTHREADS)
|
||||
MOZ_CHECK_HEADERS(pthread.h)
|
||||
fi
|
||||
|
||||
|
||||
|
||||
@@ -3269,14 +3269,14 @@ nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver)
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::NotifyAsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos)
|
||||
nsDocShell::NotifyAsyncPanZoomStarted()
|
||||
{
|
||||
nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
|
||||
while (iter.HasMore()) {
|
||||
nsWeakPtr ref = iter.GetNext();
|
||||
nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
|
||||
if (obs) {
|
||||
obs->AsyncPanZoomStarted(aScrollPos);
|
||||
obs->AsyncPanZoomStarted();
|
||||
} else {
|
||||
mScrollObservers.RemoveElement(ref);
|
||||
}
|
||||
@@ -3287,20 +3287,20 @@ nsDocShell::NotifyAsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos)
|
||||
nsCOMPtr<nsIDocShell> kid = do_QueryInterface(ChildAt(i));
|
||||
if (kid) {
|
||||
nsDocShell* docShell = static_cast<nsDocShell*>(kid.get());
|
||||
docShell->NotifyAsyncPanZoomStarted(aScrollPos);
|
||||
docShell->NotifyAsyncPanZoomStarted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::NotifyAsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos)
|
||||
nsDocShell::NotifyAsyncPanZoomStopped()
|
||||
{
|
||||
nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
|
||||
while (iter.HasMore()) {
|
||||
nsWeakPtr ref = iter.GetNext();
|
||||
nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
|
||||
if (obs) {
|
||||
obs->AsyncPanZoomStopped(aScrollPos);
|
||||
obs->AsyncPanZoomStopped();
|
||||
} else {
|
||||
mScrollObservers.RemoveElement(ref);
|
||||
}
|
||||
@@ -3311,7 +3311,7 @@ nsDocShell::NotifyAsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos)
|
||||
nsCOMPtr<nsIDocShell> kid = do_QueryInterface(ChildAt(i));
|
||||
if (kid) {
|
||||
nsDocShell* docShell = static_cast<nsDocShell*>(kid.get());
|
||||
docShell->NotifyAsyncPanZoomStopped(aScrollPos);
|
||||
docShell->NotifyAsyncPanZoomStopped();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,10 +255,10 @@ public:
|
||||
|
||||
// Notify Scroll observers when an async panning/zooming transform
|
||||
// has started being applied
|
||||
void NotifyAsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos);
|
||||
void NotifyAsyncPanZoomStarted();
|
||||
// Notify Scroll observers when an async panning/zooming transform
|
||||
// is no longer applied
|
||||
void NotifyAsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos);
|
||||
void NotifyAsyncPanZoomStopped();
|
||||
|
||||
// Add new profile timeline markers to this docShell. This will only add
|
||||
// markers if the docShell is currently recording profile timeline markers.
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
#include "Units.h"
|
||||
|
||||
#define NS_ISCROLLOBSERVER_IID \
|
||||
{ 0x00bc10e3, 0xaa59, 0x4aa3, \
|
||||
{ 0x88, 0xe9, 0x43, 0x0a, 0x01, 0xa3, 0x88, 0x04 } }
|
||||
{ 0xaa5026eb, 0x2f88, 0x4026, \
|
||||
{ 0xa4, 0x6b, 0xf4, 0x59, 0x6b, 0x4e, 0xdf, 0x00 } }
|
||||
|
||||
class nsIScrollObserver : public nsISupports
|
||||
{
|
||||
@@ -28,13 +28,13 @@ public:
|
||||
* Called when an async panning/zooming transform has started being applied
|
||||
* and passed the scroll offset
|
||||
*/
|
||||
virtual void AsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos) {};
|
||||
virtual void AsyncPanZoomStarted() {};
|
||||
|
||||
/**
|
||||
* Called when an async panning/zooming transform is no longer applied
|
||||
* and passed the scroll offset
|
||||
*/
|
||||
virtual void AsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos) {};
|
||||
virtual void AsyncPanZoomStopped() {};
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScrollObserver, NS_ISCROLLOBSERVER_IID)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "nsFocusManager.h"
|
||||
|
||||
#include "AccessibleCaretEventHub.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsContentUtils.h"
|
||||
@@ -1671,6 +1672,11 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
|
||||
selectionCarets->NotifyBlur(aIsLeavingDocument || !mActiveWindow);
|
||||
}
|
||||
|
||||
nsRefPtr<AccessibleCaretEventHub> eventHub = presShell->GetAccessibleCaretEventHub();
|
||||
if (eventHub) {
|
||||
eventHub->NotifyBlur(aIsLeavingDocument || !mActiveWindow);
|
||||
}
|
||||
|
||||
// at this point, it is expected that this window will be still be
|
||||
// focused, but the focused content will be null, as it was cleared before
|
||||
// the event. If this isn't the case, then something else was focused during
|
||||
|
||||
@@ -806,7 +806,7 @@ MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
|
||||
{
|
||||
MOZ_ASSERT(rval.isString());
|
||||
JSString* str = rval.toString();
|
||||
if (JS::GetTenuredGCThingZone(str) != js::GetContextZone(cx)) {
|
||||
if (JS::GetStringZone(str) != js::GetContextZone(cx)) {
|
||||
return JS_WrapValue(cx, rval);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -261,6 +261,14 @@ DOMInterfaces = {
|
||||
'concrete': False
|
||||
},
|
||||
|
||||
'ChromeUtils': {
|
||||
# The codegen is dumb, and doesn't understand that this interface is only a
|
||||
# collection of static methods, so we have this `concrete: False` hack.
|
||||
'concrete': False,
|
||||
'nativeType': 'mozilla::devtools::ChromeUtils',
|
||||
'implicitJSContext': ['readHeapSnapshot', 'saveHeapSnapshot']
|
||||
},
|
||||
|
||||
'ChromeWindow': {
|
||||
'concrete': False,
|
||||
},
|
||||
@@ -488,6 +496,10 @@ DOMInterfaces = {
|
||||
'headerFile': 'nsGeolocation.h'
|
||||
},
|
||||
|
||||
'HeapSnapshot': {
|
||||
'nativeType': 'mozilla::devtools::HeapSnapshot'
|
||||
},
|
||||
|
||||
'History': {
|
||||
'headerFile': 'nsHistory.h',
|
||||
'nativeType': 'nsHistory'
|
||||
|
||||
@@ -576,8 +576,6 @@ BrowserElementChild.prototype = {
|
||||
e.stopPropagation();
|
||||
let detail = {
|
||||
state: e.state,
|
||||
scrollX: e.scrollX,
|
||||
scrollY: e.scrollY,
|
||||
};
|
||||
sendAsyncMsg('scrollviewchange', detail);
|
||||
},
|
||||
|
||||
@@ -62,8 +62,6 @@ using namespace std;
|
||||
|
||||
#define PLUGIN_VERSION "1.0.0.0"
|
||||
#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
|
||||
#define STATIC_ASSERT(condition) \
|
||||
extern void np_static_assert(int arg[(condition) ? 1 : -1])
|
||||
|
||||
extern const char *sPluginName;
|
||||
extern const char *sPluginDescription;
|
||||
@@ -305,8 +303,9 @@ static const ScriptableFunction sPluginMethodFunctions[] = {
|
||||
echoString,
|
||||
};
|
||||
|
||||
STATIC_ASSERT(ARRAY_LENGTH(sPluginMethodIdentifierNames) ==
|
||||
ARRAY_LENGTH(sPluginMethodFunctions));
|
||||
static_assert(ARRAY_LENGTH(sPluginMethodIdentifierNames) ==
|
||||
ARRAY_LENGTH(sPluginMethodFunctions),
|
||||
"Arrays should have the same size");
|
||||
|
||||
static const NPUTF8* sPluginPropertyIdentifierNames[] = {
|
||||
"propertyAndMethod"
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A collection of static utility methods that are only exposed to Chrome.
|
||||
*/
|
||||
[ChromeOnly, Exposed=(Window,System)]
|
||||
interface ChromeUtils {
|
||||
/**
|
||||
* Serialize a snapshot of the heap graph, as seen by |JS::ubi::Node| and
|
||||
* restricted by |boundaries|, and write it to the provided file path.
|
||||
*
|
||||
* @param filePath The file path to write the heap snapshot to.
|
||||
*
|
||||
* @param boundaries The portion of the heap graph to write.
|
||||
*/
|
||||
[Throws]
|
||||
static void saveHeapSnapshot(DOMString filePath,
|
||||
optional HeapSnapshotBoundaries boundaries);
|
||||
|
||||
/**
|
||||
* Deserialize a core dump into a HeapSnapshot.
|
||||
*
|
||||
* @param filePath The file path to read the core dump from.
|
||||
*/
|
||||
[Throws, NewObject]
|
||||
static HeapSnapshot readHeapSnapshot(DOMString filePath);
|
||||
};
|
||||
|
||||
/**
|
||||
* A JS object whose properties specify what portion of the heap graph to
|
||||
* write. The recognized properties are:
|
||||
*
|
||||
* * globals: [ global, ... ]
|
||||
* Dump only nodes that either:
|
||||
* - belong in the compartment of one of the given globals;
|
||||
* - belong to no compartment, but do belong to a Zone that contains one of
|
||||
* the given globals;
|
||||
* - are referred to directly by one of the last two kinds of nodes; or
|
||||
* - is the fictional root node, described below.
|
||||
*
|
||||
* * debugger: Debugger object
|
||||
* Like "globals", but use the Debugger's debuggees as the globals.
|
||||
*
|
||||
* * runtime: true
|
||||
* Dump the entire heap graph, starting with the JSRuntime's roots.
|
||||
*
|
||||
* One, and only one, of these properties must exist on the boundaries object.
|
||||
*
|
||||
* The root of the dumped graph is a fictional node whose ubi::Node type name is
|
||||
* "CoreDumpRoot". If we are dumping the entire ubi::Node graph, this root node
|
||||
* has an edge for each of the JSRuntime's roots. If we are dumping a selected
|
||||
* set of globals, the root has an edge to each global, and an edge for each
|
||||
* incoming JS reference to the selected Zones.
|
||||
*/
|
||||
dictionary HeapSnapshotBoundaries {
|
||||
sequence<object> globals;
|
||||
object debugger;
|
||||
boolean runtime;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A HeapSnapshot represents a snapshot of the heap graph
|
||||
*/
|
||||
[ChromeOnly, Exposed=(Window,System)]
|
||||
interface HeapSnapshot {
|
||||
};
|
||||
@@ -8,14 +8,10 @@ enum ScrollState {"started", "stopped"};
|
||||
|
||||
dictionary ScrollViewChangeEventInit : EventInit {
|
||||
ScrollState state = "started";
|
||||
float scrollX = 0;
|
||||
float scrollY = 0;
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional ScrollViewChangeEventInit eventInit),
|
||||
ChromeOnly]
|
||||
interface ScrollViewChangeEvent : Event {
|
||||
readonly attribute ScrollState state;
|
||||
readonly attribute float scrollX;
|
||||
readonly attribute float scrollY;
|
||||
};
|
||||
|
||||
@@ -73,6 +73,7 @@ WEBIDL_FILES = [
|
||||
'CharacterData.webidl',
|
||||
'ChildNode.webidl',
|
||||
'ChromeNotifications.webidl',
|
||||
'ChromeUtils.webidl',
|
||||
'Client.webidl',
|
||||
'Clients.webidl',
|
||||
'ClipboardEvent.webidl',
|
||||
@@ -158,6 +159,7 @@ WEBIDL_FILES = [
|
||||
'GetUserMediaRequest.webidl',
|
||||
'HDMIInputPort.webidl',
|
||||
'Headers.webidl',
|
||||
'HeapSnapshot.webidl',
|
||||
'History.webidl',
|
||||
'HTMLAllCollection.webidl',
|
||||
'HTMLAnchorElement.webidl',
|
||||
|
||||
+168
-48
@@ -225,10 +225,9 @@ public:
|
||||
|
||||
virtual ~DebugGLData() { }
|
||||
|
||||
Packet::DataType GetDataType() const { return mDataType; }
|
||||
|
||||
virtual bool Write() = 0;
|
||||
|
||||
protected:
|
||||
static bool WriteToStream(Packet& aPacket) {
|
||||
if (!WebSocketHelper::GetSocketManager())
|
||||
return true;
|
||||
@@ -239,11 +238,10 @@ public:
|
||||
return WebSocketHelper::GetSocketManager()->WriteAll(data.get(), size);
|
||||
}
|
||||
|
||||
protected:
|
||||
Packet::DataType mDataType;
|
||||
};
|
||||
|
||||
class DebugGLFrameStatusData : public DebugGLData
|
||||
class DebugGLFrameStatusData final: public DebugGLData
|
||||
{
|
||||
public:
|
||||
DebugGLFrameStatusData(Packet::DataType aDataType,
|
||||
@@ -257,8 +255,6 @@ public:
|
||||
mFrameStamp(0)
|
||||
{ }
|
||||
|
||||
int64_t GetFrameStamp() const { return mFrameStamp; }
|
||||
|
||||
virtual bool Write() override {
|
||||
Packet packet;
|
||||
packet.set_type(mDataType);
|
||||
@@ -266,16 +262,14 @@ public:
|
||||
FramePacket* fp = packet.mutable_frame();
|
||||
fp->set_value(static_cast<uint64_t>(mFrameStamp));
|
||||
|
||||
if (!WriteToStream(packet))
|
||||
return false;
|
||||
return true;
|
||||
return WriteToStream(packet);
|
||||
}
|
||||
|
||||
protected:
|
||||
int64_t mFrameStamp;
|
||||
};
|
||||
|
||||
class DebugGLTextureData : public DebugGLData {
|
||||
class DebugGLTextureData final: public DebugGLData {
|
||||
public:
|
||||
DebugGLTextureData(GLContext* cx,
|
||||
void* layerRef,
|
||||
@@ -283,7 +277,7 @@ public:
|
||||
GLuint name,
|
||||
DataSourceSurface* img)
|
||||
: DebugGLData(Packet::TEXTURE),
|
||||
mLayerRef(layerRef),
|
||||
mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
|
||||
mTarget(target),
|
||||
mName(name),
|
||||
mContextAddress(reinterpret_cast<intptr_t>(cx)),
|
||||
@@ -296,16 +290,8 @@ public:
|
||||
pack(img);
|
||||
}
|
||||
|
||||
const void* GetLayerRef() const { return mLayerRef; }
|
||||
GLuint GetName() const { return mName; }
|
||||
GLenum GetTextureTarget() const { return mTarget; }
|
||||
intptr_t GetContextAddress() const { return mContextAddress; }
|
||||
uint32_t GetDataSize() const { return mDatasize; }
|
||||
|
||||
virtual bool Write() override {
|
||||
if (!WriteToStream(mPacket))
|
||||
return false;
|
||||
return true;
|
||||
return WriteToStream(mPacket);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -313,7 +299,7 @@ private:
|
||||
mPacket.set_type(mDataType);
|
||||
|
||||
TexturePacket* tp = mPacket.mutable_texture();
|
||||
tp->set_layerref(reinterpret_cast<uint64_t>(mLayerRef));
|
||||
tp->set_layerref(mLayerRef);
|
||||
tp->set_name(mName);
|
||||
tp->set_target(mTarget);
|
||||
tp->set_dataformat(LOCAL_GL_RGBA);
|
||||
@@ -351,7 +337,7 @@ private:
|
||||
}
|
||||
|
||||
protected:
|
||||
void* mLayerRef;
|
||||
uint64_t mLayerRef;
|
||||
GLenum mTarget;
|
||||
GLuint mName;
|
||||
intptr_t mContextAddress;
|
||||
@@ -361,44 +347,38 @@ protected:
|
||||
Packet mPacket;
|
||||
};
|
||||
|
||||
class DebugGLColorData : public DebugGLData {
|
||||
class DebugGLColorData final: public DebugGLData {
|
||||
public:
|
||||
DebugGLColorData(void* layerRef,
|
||||
const gfxRGBA& color,
|
||||
int width,
|
||||
int height)
|
||||
: DebugGLData(Packet::COLOR),
|
||||
mLayerRef(layerRef),
|
||||
mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
|
||||
mColor(color.Packed()),
|
||||
mSize(width, height)
|
||||
{ }
|
||||
|
||||
const void* GetLayerRef() const { return mLayerRef; }
|
||||
uint32_t GetColor() const { return mColor; }
|
||||
const nsIntSize& GetSize() const { return mSize; }
|
||||
|
||||
virtual bool Write() override {
|
||||
Packet packet;
|
||||
packet.set_type(mDataType);
|
||||
|
||||
ColorPacket* cp = packet.mutable_color();
|
||||
cp->set_layerref(reinterpret_cast<uint64_t>(mLayerRef));
|
||||
cp->set_layerref(mLayerRef);
|
||||
cp->set_color(mColor);
|
||||
cp->set_width(mSize.width);
|
||||
cp->set_height(mSize.height);
|
||||
|
||||
if (!WriteToStream(packet))
|
||||
return false;
|
||||
return true;
|
||||
return WriteToStream(packet);
|
||||
}
|
||||
|
||||
protected:
|
||||
void* mLayerRef;
|
||||
uint64_t mLayerRef;
|
||||
uint32_t mColor;
|
||||
nsIntSize mSize;
|
||||
};
|
||||
|
||||
class DebugGLLayersData : public DebugGLData {
|
||||
class DebugGLLayersData final: public DebugGLData {
|
||||
public:
|
||||
explicit DebugGLLayersData(UniquePtr<Packet> aPacket)
|
||||
: DebugGLData(Packet::LAYERS),
|
||||
@@ -407,17 +387,14 @@ public:
|
||||
|
||||
virtual bool Write() override {
|
||||
mPacket->set_type(mDataType);
|
||||
|
||||
if (!WriteToStream(*mPacket))
|
||||
return false;
|
||||
return true;
|
||||
return WriteToStream(*mPacket);
|
||||
}
|
||||
|
||||
protected:
|
||||
UniquePtr<Packet> mPacket;
|
||||
};
|
||||
|
||||
class DebugGLMetaData : public DebugGLData
|
||||
class DebugGLMetaData final: public DebugGLData
|
||||
{
|
||||
public:
|
||||
DebugGLMetaData(Packet::DataType aDataType,
|
||||
@@ -438,15 +415,69 @@ public:
|
||||
MetaPacket* mp = packet.mutable_meta();
|
||||
mp->set_composedbyhwc(mComposedByHwc);
|
||||
|
||||
if (!WriteToStream(packet))
|
||||
return false;
|
||||
return true;
|
||||
return WriteToStream(packet);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool mComposedByHwc;
|
||||
};
|
||||
|
||||
class DebugGLDrawData final: public DebugGLData {
|
||||
public:
|
||||
DebugGLDrawData(float aOffsetX,
|
||||
float aOffsetY,
|
||||
const gfx::Matrix4x4& aMVMatrix,
|
||||
size_t aRects,
|
||||
const gfx::Rect* aLayerRects,
|
||||
void* aLayerRef)
|
||||
: DebugGLData(Packet::DRAW),
|
||||
mOffsetX(aOffsetX),
|
||||
mOffsetY(aOffsetY),
|
||||
mMVMatrix(aMVMatrix),
|
||||
mRects(aRects),
|
||||
mLayerRef(reinterpret_cast<uint64_t>(aLayerRef))
|
||||
{
|
||||
for (size_t i = 0; i < mRects; i++){
|
||||
mLayerRects[i] = aLayerRects[i];
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool Write() override {
|
||||
Packet packet;
|
||||
packet.set_type(mDataType);
|
||||
|
||||
DrawPacket* dp = packet.mutable_draw();
|
||||
dp->set_layerref(mLayerRef);
|
||||
|
||||
dp->set_offsetx(mOffsetX);
|
||||
dp->set_offsety(mOffsetY);
|
||||
|
||||
auto element = reinterpret_cast<Float *>(&mMVMatrix);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
dp->add_mvmatrix(*element++);
|
||||
}
|
||||
dp->set_totalrects(mRects);
|
||||
|
||||
MOZ_ASSERT(mRects > 0 && mRects < 4);
|
||||
for (size_t i = 0; i < mRects; i++) {
|
||||
layerscope::DrawPacket::Rect* pRect = dp->add_layerrect();
|
||||
pRect->set_x(mLayerRects[i].x);
|
||||
pRect->set_y(mLayerRects[i].y);
|
||||
pRect->set_w(mLayerRects[i].width);
|
||||
pRect->set_h(mLayerRects[i].height);
|
||||
}
|
||||
|
||||
return WriteToStream(packet);
|
||||
}
|
||||
|
||||
protected:
|
||||
float mOffsetX;
|
||||
float mOffsetY;
|
||||
gfx::Matrix4x4 mMVMatrix;
|
||||
size_t mRects;
|
||||
gfx::Rect mLayerRects[4];
|
||||
uint64_t mLayerRef;
|
||||
};
|
||||
|
||||
class DebugListener : public nsIServerSocketListener
|
||||
{
|
||||
@@ -772,7 +803,6 @@ SenderHelper::SendEffectChain(GLContext* aGLContext,
|
||||
// TODO:
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------
|
||||
// LayerScopeWebSocketHandler implementation
|
||||
// ----------------------------------------------
|
||||
@@ -1265,16 +1295,107 @@ LayerScope::Init()
|
||||
}
|
||||
}
|
||||
|
||||
class DrawSession {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(DrawSession)
|
||||
|
||||
DrawSession()
|
||||
: mOffsetX(0.0),
|
||||
mOffsetY(0.0),
|
||||
mRects(0)
|
||||
{ }
|
||||
|
||||
float mOffsetX;
|
||||
float mOffsetY;
|
||||
gfx::Matrix4x4 mMVMatrix;
|
||||
size_t mRects;
|
||||
gfx::Rect mLayerRects[4];
|
||||
private:
|
||||
~DrawSession() {}
|
||||
};
|
||||
|
||||
class DrawSessionHolder {
|
||||
public:
|
||||
static void setSession(DrawSession *aSession) {
|
||||
mSession = aSession;
|
||||
}
|
||||
|
||||
static DrawSession& current() {
|
||||
return *mSession;
|
||||
}
|
||||
|
||||
private:
|
||||
static nsRefPtr<DrawSession> mSession;
|
||||
};
|
||||
|
||||
nsRefPtr<DrawSession> DrawSessionHolder::mSession;
|
||||
|
||||
void
|
||||
LayerScope::SendEffectChain(gl::GLContext* aGLContext,
|
||||
const EffectChain& aEffectChain,
|
||||
int aWidth,
|
||||
int aHeight)
|
||||
LayerScope::DrawBegin()
|
||||
{
|
||||
if (!CheckSendable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DrawSessionHolder::setSession(new DrawSession());
|
||||
}
|
||||
|
||||
void LayerScope::SetRenderOffset(float aX, float aY)
|
||||
{
|
||||
if (!CheckSendable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DrawSessionHolder::current().mOffsetX = aX;
|
||||
DrawSessionHolder::current().mOffsetY = aY;
|
||||
}
|
||||
|
||||
void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix)
|
||||
{
|
||||
if (!CheckSendable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DrawSessionHolder::current().mMVMatrix = aMatrix;
|
||||
}
|
||||
|
||||
void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects)
|
||||
{
|
||||
if (!CheckSendable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aRects > 0 && aRects <= 4);
|
||||
MOZ_ASSERT(aLayerRects);
|
||||
|
||||
DrawSessionHolder::current().mRects = aRects;
|
||||
|
||||
for (size_t i = 0; i < aRects; i++){
|
||||
DrawSessionHolder::current().mLayerRects[i] = aLayerRects[i];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerScope::DrawEnd(gl::GLContext* aGLContext,
|
||||
const EffectChain& aEffectChain,
|
||||
int aWidth,
|
||||
int aHeight)
|
||||
{
|
||||
// Protect this public function
|
||||
if (!CheckSendable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Send parameters of draw call, such as uniforms and attributes of
|
||||
// vertex adnd fragment shader.
|
||||
DrawSession& draws = DrawSessionHolder::current();
|
||||
WebSocketHelper::GetSocketManager()->AppendDebugData(
|
||||
new DebugGLDrawData(draws.mOffsetX, draws.mOffsetY,
|
||||
draws.mMVMatrix, draws.mRects,
|
||||
draws.mLayerRects,
|
||||
aEffectChain.mLayerRef));
|
||||
|
||||
// 2. Send textures.
|
||||
SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight);
|
||||
}
|
||||
|
||||
@@ -1328,7 +1449,6 @@ LayerScope::CleanLayer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LayerScope::SetHWComposed()
|
||||
{
|
||||
|
||||
@@ -23,10 +23,15 @@ class LayerComposite;
|
||||
|
||||
class LayerScope {
|
||||
public:
|
||||
static void SendEffectChain(gl::GLContext* aGLContext,
|
||||
const EffectChain& aEffectChain,
|
||||
int aWidth,
|
||||
int aHeight);
|
||||
static void DrawBegin();
|
||||
static void SetRenderOffset(float aX, float aY);
|
||||
static void SetLayerTransform(const gfx::Matrix4x4& aMatrix);
|
||||
static void SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects);
|
||||
static void DrawEnd(gl::GLContext* aGLContext,
|
||||
const EffectChain& aEffectChain,
|
||||
int aWidth,
|
||||
int aHeight);
|
||||
|
||||
static void SendLayer(LayerComposite* aLayer,
|
||||
int aWidth,
|
||||
int aHeight);
|
||||
|
||||
@@ -1712,6 +1712,25 @@ Layer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
|
||||
if (!mVisibleRegion.IsEmpty()) {
|
||||
DumpRegion(layer->mutable_vregion(), mVisibleRegion);
|
||||
}
|
||||
// EventRegions
|
||||
if (!mEventRegions.IsEmpty()) {
|
||||
const EventRegions &e = mEventRegions;
|
||||
if (!e.mHitRegion.IsEmpty()) {
|
||||
DumpRegion(layer->mutable_hitregion(), e.mHitRegion);
|
||||
}
|
||||
if (!e.mDispatchToContentHitRegion.IsEmpty()) {
|
||||
DumpRegion(layer->mutable_dispatchregion(), e.mDispatchToContentHitRegion);
|
||||
}
|
||||
if (!e.mNoActionRegion.IsEmpty()) {
|
||||
DumpRegion(layer->mutable_noactionregion(), e.mNoActionRegion);
|
||||
}
|
||||
if (!e.mHorizontalPanRegion.IsEmpty()) {
|
||||
DumpRegion(layer->mutable_hpanregion(), e.mHorizontalPanRegion);
|
||||
}
|
||||
if (!e.mVerticalPanRegion.IsEmpty()) {
|
||||
DumpRegion(layer->mutable_vpanregion(), e.mVerticalPanRegion);
|
||||
}
|
||||
}
|
||||
// Opacity
|
||||
layer->set_opacity(mOpacity);
|
||||
// Content opaque
|
||||
|
||||
@@ -344,7 +344,7 @@ APZEventState::ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
|
||||
nsCOMPtr<nsIDocShell> docshell(aDocument->GetDocShell());
|
||||
if (docshell && sf) {
|
||||
nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
|
||||
nsdocshell->NotifyAsyncPanZoomStarted(sf->GetScrollPositionCSSPixels());
|
||||
nsdocshell->NotifyAsyncPanZoomStarted();
|
||||
}
|
||||
}
|
||||
mActiveAPZTransforms++;
|
||||
@@ -366,7 +366,7 @@ APZEventState::ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
|
||||
nsCOMPtr<nsIDocShell> docshell(aDocument->GetDocShell());
|
||||
if (docshell && sf) {
|
||||
nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
|
||||
nsdocshell->NotifyAsyncPanZoomStopped(sf->GetScrollPositionCSSPixels());
|
||||
nsdocshell->NotifyAsyncPanZoomStopped();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -425,6 +425,7 @@ CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
|
||||
aTexCoordRect,
|
||||
&layerRects,
|
||||
&textureRects);
|
||||
|
||||
BindAndDrawQuads(aProg, rects, layerRects, textureRects);
|
||||
}
|
||||
|
||||
@@ -912,6 +913,7 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
DrawVRDistortion(aRect, aClipRect, aEffectChain, aOpacity, aTransform);
|
||||
return;
|
||||
}
|
||||
LayerScope::DrawBegin();
|
||||
|
||||
Rect clipRect = aClipRect;
|
||||
// aClipRect is in destination coordinate space (after all
|
||||
@@ -927,9 +929,6 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
gl()->fScissor(intClipRect.x, FlipY(intClipRect.y + intClipRect.height),
|
||||
intClipRect.width, intClipRect.height);
|
||||
|
||||
LayerScope::SendEffectChain(mGLContext, aEffectChain,
|
||||
aRect.width, aRect.height);
|
||||
|
||||
MaskType maskType;
|
||||
EffectMask* effectMask;
|
||||
TextureSourceOGL* sourceMask = nullptr;
|
||||
@@ -1002,7 +1001,7 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
ActivateProgram(program);
|
||||
program->SetProjectionMatrix(mProjMatrix);
|
||||
program->SetLayerTransform(aTransform);
|
||||
|
||||
LayerScope::SetLayerTransform(aTransform);
|
||||
if (colorMatrix) {
|
||||
EffectColorMatrix* effectColorMatrix =
|
||||
static_cast<EffectColorMatrix*>(aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get());
|
||||
@@ -1011,6 +1010,8 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
|
||||
IntPoint offset = mCurrentRenderTarget->GetOrigin();
|
||||
program->SetRenderOffset(offset.x, offset.y);
|
||||
LayerScope::SetRenderOffset(offset.x, offset.y);
|
||||
|
||||
if (aOpacity != 1.f)
|
||||
program->SetLayerOpacity(aOpacity);
|
||||
if (config.mFeatures & ENABLE_TEXTURE_RECT) {
|
||||
@@ -1209,6 +1210,7 @@ CompositorOGL::DrawQuad(const Rect& aRect,
|
||||
|
||||
// in case rendering has used some other GL context
|
||||
MakeCurrent();
|
||||
LayerScope::DrawEnd(mGLContext, aEffectChain, aRect.width, aRect.height);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1471,6 +1473,7 @@ CompositorOGL::BindAndDrawQuads(ShaderProgramOGL *aProg,
|
||||
// We are using GL_TRIANGLES here because the Mac Intel drivers fail to properly
|
||||
// process uniform arrays with GL_TRIANGLE_STRIP. Go figure.
|
||||
mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads);
|
||||
LayerScope::SetLayerRects(aQuads, aLayerRects);
|
||||
}
|
||||
|
||||
GLBlitTextureImageHelper*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -97,6 +97,11 @@ message LayersPacket {
|
||||
optional ScrollingDirect direct = 17;
|
||||
optional uint64 barID = 18;
|
||||
optional uint64 mask = 19; // mask layer
|
||||
optional Region hitRegion = 20;
|
||||
optional Region dispatchRegion = 21;
|
||||
optional Region noActionRegion = 22;
|
||||
optional Region hPanRegion = 23;
|
||||
optional Region vPanRegion = 24;
|
||||
|
||||
// Specific info (100 to max)
|
||||
// Painted Layer
|
||||
@@ -117,6 +122,22 @@ message MetaPacket {
|
||||
optional bool composedByHwc = 1;
|
||||
}
|
||||
|
||||
message DrawPacket {
|
||||
message Rect {
|
||||
required float x = 1;
|
||||
required float y = 2;
|
||||
required float w = 3;
|
||||
required float h = 4;
|
||||
}
|
||||
|
||||
required float offsetX = 1;
|
||||
required float offsetY = 2;
|
||||
repeated float mvMatrix = 3;
|
||||
required uint32 totalRects = 4;
|
||||
repeated Rect layerRect = 5;
|
||||
required uint64 layerref = 6;
|
||||
}
|
||||
|
||||
// We only need to use this Packet.
|
||||
// Other packet definitions are just type defines
|
||||
message Packet {
|
||||
@@ -127,6 +148,7 @@ message Packet {
|
||||
TEXTURE = 4;
|
||||
LAYERS = 5;
|
||||
META = 6;
|
||||
DRAW = 7;
|
||||
}
|
||||
required DataType type = 1;
|
||||
|
||||
@@ -135,6 +157,7 @@ message Packet {
|
||||
optional TexturePacket texture = 4;
|
||||
optional LayersPacket layers = 5;
|
||||
optional MetaPacket meta = 6;
|
||||
optional DrawPacket draw = 7;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+13
-2
@@ -262,7 +262,13 @@ class BuilderOrigin : public Builder {
|
||||
|
||||
// Tell Debuggers in |runtime| to use |mallocSizeOf| to find the size of
|
||||
// malloc'd blocks.
|
||||
void SetDebuggerMallocSizeOf(JSRuntime* runtime, mozilla::MallocSizeOf mallocSizeOf);
|
||||
JS_PUBLIC_API(void)
|
||||
SetDebuggerMallocSizeOf(JSRuntime* runtime, mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
||||
// Get the MallocSizeOf function that the given runtime is using to find the
|
||||
// size of malloc'd blocks.
|
||||
JS_PUBLIC_API(mozilla::MallocSizeOf)
|
||||
GetDebuggerMallocSizeOf(JSRuntime* runtime);
|
||||
|
||||
|
||||
|
||||
@@ -316,7 +322,12 @@ onPromiseSettled(JSContext* cx, HandleObject promise);
|
||||
|
||||
// Return true if the given value is a Debugger object, false otherwise.
|
||||
JS_PUBLIC_API(bool)
|
||||
IsDebugger(JS::Value val);
|
||||
IsDebugger(const JSObject& obj);
|
||||
|
||||
// Append each of the debuggee global objects observed by the Debugger object
|
||||
// |dbgObj| to |vector|. Returns true on success, false on failure.
|
||||
JS_PUBLIC_API(bool)
|
||||
GetDebuggeeGlobals(JSContext* cx, const JSObject& dbgObj, AutoObjectVector& vector);
|
||||
|
||||
|
||||
// Hooks for reporting where JavaScript execution began.
|
||||
|
||||
+11
-5
@@ -328,10 +328,16 @@ IsInsideNursery(const js::gc::Cell* cell)
|
||||
namespace JS {
|
||||
|
||||
static MOZ_ALWAYS_INLINE Zone*
|
||||
GetTenuredGCThingZone(void* thing)
|
||||
GetTenuredGCThingZone(GCCellPtr thing)
|
||||
{
|
||||
MOZ_ASSERT(!js::gc::IsInsideNursery((js::gc::Cell*)thing));
|
||||
return js::gc::detail::GetGCThingZone(uintptr_t(thing));
|
||||
MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell()));
|
||||
return js::gc::detail::GetGCThingZone(thing.unsafeAsUIntPtr());
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE Zone*
|
||||
GetStringZone(JSString* str)
|
||||
{
|
||||
return js::gc::detail::GetGCThingZone(uintptr_t(str));
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(Zone*)
|
||||
@@ -382,9 +388,9 @@ IsIncrementalBarrierNeededOnTenuredGCThing(JS::shadow::Runtime* rt, const JS::GC
|
||||
{
|
||||
MOZ_ASSERT(thing);
|
||||
MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell()));
|
||||
if (!rt->needsIncrementalBarrier())
|
||||
if (rt->isHeapBusy())
|
||||
return false;
|
||||
JS::Zone* zone = JS::GetTenuredGCThingZone(thing.asCell());
|
||||
JS::Zone* zone = JS::GetTenuredGCThingZone(thing);
|
||||
return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier();
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace JS {
|
||||
_(CantInlineNoBaseline) \
|
||||
_(CantInlineLazy) \
|
||||
_(CantInlineNotConstructor) \
|
||||
_(CantInlineClassConstructor) \
|
||||
_(CantInlineDisabledIon) \
|
||||
_(CantInlineTooManyArgs) \
|
||||
_(CantInlineRecursive) \
|
||||
|
||||
+90
-23
@@ -93,7 +93,7 @@
|
||||
// represented by a "rope", a structure that points to the two original
|
||||
// strings.
|
||||
//
|
||||
|
||||
//
|
||||
// We intend to use ubi::Node to write tools that report memory usage, so it's
|
||||
// important that ubi::Node accurately portray how much memory nodes consume.
|
||||
// Thus, for example, when data that apparently belongs to multiple nodes is
|
||||
@@ -142,15 +142,26 @@
|
||||
namespace JS {
|
||||
namespace ubi {
|
||||
|
||||
using mozilla::Maybe;
|
||||
using mozilla::UniquePtr;
|
||||
|
||||
class Edge;
|
||||
class EdgeRange;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
template<>
|
||||
class DefaultDelete<JS::ubi::EdgeRange> : public JS::DeletePolicy<JS::ubi::EdgeRange> { };
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
namespace ubi {
|
||||
|
||||
using mozilla::Maybe;
|
||||
using mozilla::UniquePtr;
|
||||
|
||||
// The base class implemented by each ubi::Node referent type. Subclasses must
|
||||
// not add data members to this class.
|
||||
class Base {
|
||||
class JS_FRIEND_API(Base) {
|
||||
friend class Node;
|
||||
|
||||
// For performance's sake, we'd prefer to avoid a virtual destructor; and
|
||||
@@ -176,6 +187,26 @@ class Base {
|
||||
}
|
||||
bool operator!=(const Base& rhs) const { return !(*this == rhs); }
|
||||
|
||||
// An identifier for this node, guaranteed to be stable and unique for as
|
||||
// long as this ubi::Node's referent is alive and at the same address.
|
||||
//
|
||||
// This is probably suitable for use in serializations, as it is an integral
|
||||
// type. It may also help save memory when constructing HashSets of
|
||||
// ubi::Nodes: since a uintptr_t will always be smaller than a ubi::Node, a
|
||||
// HashSet<ubi::Node::Id> will use less space per element than a
|
||||
// HashSet<ubi::Node>.
|
||||
//
|
||||
// (Note that 'unique' only means 'up to equality on ubi::Node'; see the
|
||||
// caveats about multiple objects allocated at the same address for
|
||||
// 'ubi::Node::operator=='.)
|
||||
typedef uintptr_t Id;
|
||||
virtual Id identifier() const { return reinterpret_cast<Id>(ptr); }
|
||||
|
||||
// Returns true if this node is pointing to something on the live heap, as
|
||||
// opposed to something from a deserialized core dump. Returns false,
|
||||
// otherwise.
|
||||
virtual bool isLive() const { return true; };
|
||||
|
||||
// Return a human-readable name for the referent's type. The result should
|
||||
// be statically allocated. (You can use MOZ_UTF16("strings") for this.)
|
||||
//
|
||||
@@ -190,13 +221,11 @@ class Base {
|
||||
virtual size_t size(mozilla::MallocSizeOf mallocSizeof) const { return 0; }
|
||||
|
||||
// Return an EdgeRange that initially contains all the referent's outgoing
|
||||
// edges. The EdgeRange should be freed with 'js_delete'. (You could use
|
||||
// ScopedDJSeletePtr<EdgeRange> to manage it.) On OOM, report an exception
|
||||
// on |cx| and return nullptr.
|
||||
// edges. The caller takes ownership of the EdgeRange.
|
||||
//
|
||||
// If wantNames is true, compute names for edges. Doing so can be expensive
|
||||
// in time and memory.
|
||||
virtual EdgeRange* edges(JSContext* cx, bool wantNames) const = 0;
|
||||
virtual UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const = 0;
|
||||
|
||||
// Return the Zone to which this node's referent belongs, or nullptr if the
|
||||
// referent is not of a type allocated in SpiderMonkey Zones.
|
||||
@@ -238,7 +267,7 @@ class Base {
|
||||
// Base that represents a pointer to the referent type. It must also
|
||||
// include the members described here.
|
||||
template<typename Referent>
|
||||
struct Concrete {
|
||||
struct JS_FRIEND_API(Concrete) {
|
||||
// The specific char16_t array returned by Concrete<T>::typeName.
|
||||
static const char16_t concreteTypeName[];
|
||||
|
||||
@@ -257,9 +286,9 @@ struct Concrete {
|
||||
static void construct(void* storage, Referent* referent);
|
||||
};
|
||||
|
||||
// A container for a Base instance; all members simply forward to the contained instance.
|
||||
// This container allows us to pass ubi::Node instances by value.
|
||||
class Node {
|
||||
// A container for a Base instance; all members simply forward to the contained
|
||||
// instance. This container allows us to pass ubi::Node instances by value.
|
||||
class JS_FRIEND_API(Node) {
|
||||
// Storage in which we allocate Base subclasses.
|
||||
mozilla::AlignedStorage2<Base> storage;
|
||||
Base* base() { return storage.addr(); }
|
||||
@@ -328,6 +357,8 @@ class Node {
|
||||
return base()->ptr != nullptr;
|
||||
}
|
||||
|
||||
bool isLive() const { return base()->isLive(); }
|
||||
|
||||
template<typename T>
|
||||
bool is() const {
|
||||
return base()->typeName() == Concrete<T>::concreteTypeName;
|
||||
@@ -335,12 +366,14 @@ class Node {
|
||||
|
||||
template<typename T>
|
||||
T* as() const {
|
||||
MOZ_ASSERT(isLive());
|
||||
MOZ_ASSERT(is<T>());
|
||||
return static_cast<T*>(base()->ptr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* asOrNull() const {
|
||||
MOZ_ASSERT(isLive());
|
||||
return is<T>() ? static_cast<T*>(base()->ptr) : nullptr;
|
||||
}
|
||||
|
||||
@@ -363,10 +396,13 @@ class Node {
|
||||
return base()->size(mallocSizeof);
|
||||
}
|
||||
|
||||
EdgeRange* edges(JSContext* cx, bool wantNames = true) const {
|
||||
UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames = true) const {
|
||||
return base()->edges(cx, wantNames);
|
||||
}
|
||||
|
||||
typedef Base::Id Id;
|
||||
Id identifier() const { return base()->identifier(); }
|
||||
|
||||
// A hash policy for ubi::Nodes.
|
||||
// This simply uses the stock PointerHasher on the ubi::Node's pointer.
|
||||
// We specialize DefaultHasher below to make this the default.
|
||||
@@ -486,6 +522,33 @@ class SimpleEdge : public Edge {
|
||||
|
||||
typedef mozilla::Vector<SimpleEdge, 8, js::TempAllocPolicy> SimpleEdgeVector;
|
||||
|
||||
// An EdgeRange concrete class that holds a pre-existing vector of
|
||||
// SimpleEdges. A PreComputedEdgeRange does not take ownership of its
|
||||
// SimpleEdgeVector; it is up to the PreComputedEdgeRange's consumer to manage
|
||||
// that lifetime.
|
||||
class PreComputedEdgeRange : public EdgeRange {
|
||||
SimpleEdgeVector& edges;
|
||||
size_t i;
|
||||
|
||||
void settle() {
|
||||
front_ = i < edges.length() ? &edges[i] : nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit PreComputedEdgeRange(JSContext* cx, SimpleEdgeVector& edges)
|
||||
: edges(edges),
|
||||
i(0)
|
||||
{
|
||||
settle();
|
||||
}
|
||||
|
||||
void popFront() override {
|
||||
MOZ_ASSERT(!empty());
|
||||
i++;
|
||||
settle();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// RootList is a class that can be pointed to by a |ubi::Node|, creating a
|
||||
// fictional root-of-roots which has edges to every GC root in the JS
|
||||
@@ -515,7 +578,7 @@ typedef mozilla::Vector<SimpleEdge, 8, js::TempAllocPolicy> SimpleEdgeVector;
|
||||
//
|
||||
// ...
|
||||
// }
|
||||
class MOZ_STACK_CLASS RootList {
|
||||
class MOZ_STACK_CLASS JS_FRIEND_API(RootList) {
|
||||
Maybe<AutoCheckCannotGC>& noGC;
|
||||
JSContext* cx;
|
||||
|
||||
@@ -532,6 +595,10 @@ class MOZ_STACK_CLASS RootList {
|
||||
// Find only GC roots in the given Debugger object's set of debuggee zones.
|
||||
bool init(HandleObject debuggees);
|
||||
|
||||
// Returns true if the RootList has been initialized successfully, false
|
||||
// otherwise.
|
||||
bool initialized() { return noGC.isSome(); }
|
||||
|
||||
// Explicitly add the given Node as a root in this RootList. If wantNames is
|
||||
// true, you must pass an edgeName. The RootList does not take ownership of
|
||||
// edgeName.
|
||||
@@ -542,8 +609,8 @@ class MOZ_STACK_CLASS RootList {
|
||||
// Concrete classes for ubi::Node referent types.
|
||||
|
||||
template<>
|
||||
struct Concrete<RootList> : public Base {
|
||||
EdgeRange* edges(JSContext* cx, bool wantNames) const override;
|
||||
struct JS_FRIEND_API(Concrete<RootList>) : public Base {
|
||||
UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const override;
|
||||
const char16_t* typeName() const override { return concreteTypeName; }
|
||||
|
||||
protected:
|
||||
@@ -558,9 +625,9 @@ struct Concrete<RootList> : public Base {
|
||||
// A reusable ubi::Concrete specialization base class for types supported by
|
||||
// JS_TraceChildren.
|
||||
template<typename Referent>
|
||||
class TracerConcrete : public Base {
|
||||
class JS_FRIEND_API(TracerConcrete) : public Base {
|
||||
const char16_t* typeName() const override { return concreteTypeName; }
|
||||
EdgeRange* edges(JSContext*, bool wantNames) const override;
|
||||
UniquePtr<EdgeRange> edges(JSContext*, bool wantNames) const override;
|
||||
JS::Zone* zone() const override;
|
||||
|
||||
protected:
|
||||
@@ -574,7 +641,7 @@ class TracerConcrete : public Base {
|
||||
|
||||
// For JS_TraceChildren-based types that have a 'compartment' method.
|
||||
template<typename Referent>
|
||||
class TracerConcreteWithCompartment : public TracerConcrete<Referent> {
|
||||
class JS_FRIEND_API(TracerConcreteWithCompartment) : public TracerConcrete<Referent> {
|
||||
typedef TracerConcrete<Referent> TracerBase;
|
||||
JSCompartment* compartment() const override;
|
||||
|
||||
@@ -594,7 +661,7 @@ template<> struct Concrete<JSScript> : TracerConcreteWithCompartment<JSScript> {
|
||||
|
||||
// The JSObject specialization.
|
||||
template<>
|
||||
class Concrete<JSObject> : public TracerConcreteWithCompartment<JSObject> {
|
||||
class JS_FRIEND_API(Concrete<JSObject>) : public TracerConcreteWithCompartment<JSObject> {
|
||||
const char* jsObjectClassName() const override;
|
||||
bool jsObjectConstructorName(JSContext* cx,
|
||||
UniquePtr<char16_t[], JS::FreePolicy>& outName) const override;
|
||||
@@ -622,10 +689,10 @@ template<> struct Concrete<JSString> : TracerConcrete<JSString> {
|
||||
|
||||
// The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts.
|
||||
template<>
|
||||
class Concrete<void> : public Base {
|
||||
class JS_FRIEND_API(Concrete<void>) : public Base {
|
||||
const char16_t* typeName() const override;
|
||||
size_t size(mozilla::MallocSizeOf mallocSizeOf) const override;
|
||||
EdgeRange* edges(JSContext* cx, bool wantNames) const override;
|
||||
UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const override;
|
||||
JS::Zone* zone() const override;
|
||||
JSCompartment* compartment() const override;
|
||||
|
||||
|
||||
@@ -120,13 +120,13 @@ struct BreadthFirst {
|
||||
MOZ_ASSERT(!traversalBegun);
|
||||
traversalBegun = true;
|
||||
|
||||
// While there are pending nodes, visit them, until we've found a path to the target.
|
||||
// While there are pending nodes, visit them.
|
||||
while (!pending.empty()) {
|
||||
Node origin = pending.front();
|
||||
pending.popFront();
|
||||
|
||||
// Get a range containing all origin's outgoing edges.
|
||||
js::ScopedJSDeletePtr<EdgeRange> range(origin.edges(cx, wantNames));
|
||||
auto range = origin.edges(cx, wantNames);
|
||||
if (!range)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -438,23 +438,11 @@ ScrambleHashCode(HashNumber h)
|
||||
# define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND)))
|
||||
# define STATIC_INVARIANT(COND) __attribute__((invariant(#COND)))
|
||||
# define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND)))
|
||||
# define STATIC_PASTE2(X,Y) X ## Y
|
||||
# define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y)
|
||||
# define STATIC_ASSERT(COND) \
|
||||
JS_BEGIN_MACRO \
|
||||
__attribute__((assert_static(#COND), unused)) \
|
||||
int STATIC_PASTE1(assert_static_, __COUNTER__); \
|
||||
JS_END_MACRO
|
||||
# define STATIC_ASSUME(COND) \
|
||||
JS_BEGIN_MACRO \
|
||||
__attribute__((assume_static(#COND), unused)) \
|
||||
int STATIC_PASTE1(assume_static_, __COUNTER__); \
|
||||
JS_END_MACRO
|
||||
# define STATIC_ASSERT_RUNTIME(COND) \
|
||||
JS_BEGIN_MACRO \
|
||||
__attribute__((assert_static_runtime(#COND), unused)) \
|
||||
int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \
|
||||
JS_END_MACRO
|
||||
# else /* XGILL_PLUGIN */
|
||||
# define STATIC_PRECONDITION(COND) /* nothing */
|
||||
# define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
|
||||
@@ -462,9 +450,7 @@ ScrambleHashCode(HashNumber h)
|
||||
# define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
|
||||
# define STATIC_INVARIANT(COND) /* nothing */
|
||||
# define STATIC_INVARIANT_ASSUME(COND) /* nothing */
|
||||
# define STATIC_ASSERT(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
|
||||
# define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
|
||||
# define STATIC_ASSERT_RUNTIME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
|
||||
# endif /* XGILL_PLUGIN */
|
||||
# define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
|
||||
#endif /* HAVE_STATIC_ANNOTATIONS */
|
||||
|
||||
@@ -598,6 +598,9 @@ DynamicallyLinkModule(JSContext* cx, const CallArgs& args, AsmJSModule& module)
|
||||
|
||||
module.initGlobalNaN();
|
||||
|
||||
// See the comment in AllocateExecutableMemory.
|
||||
ExecutableAllocator::makeExecutable(module.codeBase(), module.codeBytes());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,11 +62,11 @@ using mozilla::Swap;
|
||||
static uint8_t*
|
||||
AllocateExecutableMemory(ExclusiveContext* cx, size_t bytes)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
unsigned permissions = PAGE_EXECUTE_READWRITE;
|
||||
#else
|
||||
unsigned permissions = PROT_READ | PROT_WRITE | PROT_EXEC;
|
||||
#endif
|
||||
// On most platforms, this will allocate RWX memory. On iOS, or when
|
||||
// --non-writable-jitcode is used, this will allocate RW memory. In this
|
||||
// case, DynamicallyLinkModule will reprotect the code as RX.
|
||||
unsigned permissions =
|
||||
ExecutableAllocator::initialProtectionFlags(ExecutableAllocator::Writable);
|
||||
void* p = AllocateExecutableMemory(nullptr, bytes, permissions, "asm-js-code", AsmJSPageSize);
|
||||
if (!p)
|
||||
ReportOutOfMemory(cx);
|
||||
@@ -295,10 +295,9 @@ AsmJSModule::finish(ExclusiveContext* cx, TokenStream& tokenStream, MacroAssembl
|
||||
pod.srcLength_ = endBeforeCurly - srcStart_;
|
||||
pod.srcLengthWithRightBrace_ = endAfterCurly - srcStart_;
|
||||
|
||||
// The global data section sits immediately after the executable (and
|
||||
// other) data allocated by the MacroAssembler, so ensure it is
|
||||
// SIMD-aligned.
|
||||
pod.codeBytes_ = AlignBytes(masm.bytesNeeded(), SimdMemoryAlignment);
|
||||
// Start global data on a new page so JIT code may be given independent
|
||||
// protection flags.
|
||||
pod.codeBytes_ = AlignBytes(masm.bytesNeeded(), AsmJSPageSize);
|
||||
|
||||
// The entire region is allocated via mmap/VirtualAlloc which requires
|
||||
// units of pages.
|
||||
@@ -655,7 +654,7 @@ FuncCast(F* pf)
|
||||
static void*
|
||||
RedirectCall(void* fun, ABIFunctionType type)
|
||||
{
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
fun = Simulator::RedirectNativeFunction(fun, type);
|
||||
#endif
|
||||
return fun;
|
||||
@@ -938,6 +937,24 @@ AsmJSModule::restoreToInitialState(ArrayBufferObjectMaybeShared* maybePrevBuffer
|
||||
restoreHeapToInitialState(maybePrevBuffer);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class MOZ_STACK_CLASS AutoMutateCode
|
||||
{
|
||||
AutoWritableJitCode awjc_;
|
||||
AutoFlushICache afc_;
|
||||
|
||||
public:
|
||||
AutoMutateCode(JSContext* cx, AsmJSModule& module, const char* name)
|
||||
: awjc_(cx->runtime(), module.codeBase(), module.codeBytes()),
|
||||
afc_(name)
|
||||
{
|
||||
module.setAutoFlushICacheRange();
|
||||
}
|
||||
};
|
||||
|
||||
}; // anonymous namespace
|
||||
|
||||
bool
|
||||
AsmJSModule::detachHeap(JSContext* cx)
|
||||
{
|
||||
@@ -958,9 +975,7 @@ AsmJSModule::detachHeap(JSContext* cx)
|
||||
MOZ_ASSERT_IF(active(), activation()->exitReason() == AsmJSExit::Reason_JitFFI ||
|
||||
activation()->exitReason() == AsmJSExit::Reason_SlowFFI);
|
||||
|
||||
AutoFlushICache afc("AsmJSModule::detachHeap");
|
||||
setAutoFlushICacheRange();
|
||||
|
||||
AutoMutateCode amc(cx, *this, "AsmJSModule::detachHeap");
|
||||
restoreHeapToInitialState(maybeHeap_);
|
||||
|
||||
MOZ_ASSERT(hasDetachedHeap());
|
||||
@@ -1697,9 +1712,7 @@ AsmJSModule::changeHeap(Handle<ArrayBufferObject*> newHeap, JSContext* cx)
|
||||
if (interrupted_)
|
||||
return false;
|
||||
|
||||
AutoFlushICache afc("AsmJSModule::changeHeap");
|
||||
setAutoFlushICacheRange();
|
||||
|
||||
AutoMutateCode amc(cx, *this, "AsmJSModule::changeHeap");
|
||||
restoreHeapToInitialState(maybeHeap_);
|
||||
initHeap(newHeap, cx);
|
||||
return true;
|
||||
@@ -1743,9 +1756,7 @@ AsmJSModule::setProfilingEnabled(JSContext* cx, bool enabled)
|
||||
profilingLabels_.clear();
|
||||
}
|
||||
|
||||
// Conservatively flush the icache for the entire module.
|
||||
AutoFlushICache afc("AsmJSModule::setProfilingEnabled");
|
||||
setAutoFlushICacheRange();
|
||||
AutoMutateCode amc(cx, *this, "AsmJSModule::setProfilingEnabled");
|
||||
|
||||
// Patch all internal (asm.js->asm.js) callsites to call the profiling
|
||||
// prologues:
|
||||
|
||||
@@ -1165,7 +1165,7 @@ RedirectJitCodeToInterruptCheck(JSRuntime* rt, CONTEXT* context)
|
||||
if (AsmJSActivation* activation = rt->asmJSActivationStack()) {
|
||||
const AsmJSModule& module = activation->module();
|
||||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
if (module.containsFunctionPC((void*)rt->simulator()->get_pc()))
|
||||
rt->simulator()->set_resume_pc(int32_t(module.interruptExit()));
|
||||
#endif
|
||||
|
||||
@@ -104,7 +104,7 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, jsval* vp)
|
||||
if (!JS_SetProperty(cx, info, "x64", value))
|
||||
return false;
|
||||
|
||||
#ifdef JS_ARM_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM
|
||||
value = BooleanValue(true);
|
||||
#else
|
||||
value = BooleanValue(false);
|
||||
|
||||
+36
-19
@@ -3084,39 +3084,53 @@ fi
|
||||
AC_SUBST(MOZ_VALGRIND)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use ARM JIT code simulator. Requires an x86 build.
|
||||
dnl = Use a JIT code simulator for a foreign architecture.
|
||||
dnl ========================================================
|
||||
dnl Also define JS_CODEGEN_ARM in this case. If the simulator is not used,
|
||||
dnl JS_CODEGEN_foo is defined if JS_CPU_foo is defined.
|
||||
MOZ_ARG_ENABLE_BOOL(arm-simulator,
|
||||
[ --enable-arm-simulator Enable ARM simulator for JIT code],
|
||||
JS_ARM_SIMULATOR=1,
|
||||
JS_ARM_SIMULATOR= )
|
||||
MOZ_ARG_ENABLE_BOOL(mips-simulator,
|
||||
[ --enable-mips-simulator Enable MIPS simulator for JIT code],
|
||||
JS_MIPS_SIMULATOR=1,
|
||||
JS_MIPS_SIMULATOR= )
|
||||
MOZ_ARG_ENABLE_STRING(simulator,
|
||||
[ --enable-simulator=ARCH
|
||||
Enable a JIT code simulator for the specified arch.
|
||||
(arm, arm64, mips).],
|
||||
JS_SIMULATOR="$enableval")
|
||||
|
||||
if test -n "$JS_ARM_SIMULATOR" && test -n "$JS_MIPS_SIMULATOR"; then
|
||||
AC_MSG_ERROR([Flags --enable-arm-simulator and --enable-mips-simulator cannot be used together.])
|
||||
if test -n "$JS_SIMULATOR"; then
|
||||
case "$JS_SIMULATOR" in
|
||||
arm|arm64|mips) ;;
|
||||
no)
|
||||
JS_SIMULATOR=
|
||||
;;
|
||||
*) AC_MSG_ERROR([Invalid simulator. Valid simulators are: arm, arm64, mips.]) ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test -z "$ENABLE_ION"; then
|
||||
AC_DEFINE(JS_CODEGEN_NONE)
|
||||
JS_CODEGEN_NONE=1
|
||||
elif test -n "$JS_ARM_SIMULATOR"; then
|
||||
elif test "$JS_SIMULATOR" = arm; then
|
||||
if test "$CPU_ARCH" != "x86"; then
|
||||
AC_MSG_ERROR([The ARM simulator only works on x86.])
|
||||
fi
|
||||
AC_DEFINE(JS_ARM_SIMULATOR)
|
||||
AC_DEFINE(JS_SIMULATOR)
|
||||
AC_DEFINE(JS_SIMULATOR_ARM)
|
||||
AC_DEFINE(JS_CODEGEN_ARM)
|
||||
JS_SIMULATOR_ARM=1
|
||||
JS_CODEGEN_ARM=1
|
||||
elif test -n "$JS_MIPS_SIMULATOR"; then
|
||||
elif test "$JS_SIMULATOR" = arm64; then
|
||||
if test "$CPU_ARCH" != "x86_64"; then
|
||||
AC_MSG_ERROR([The ARM64 simulator only works on x86_64.])
|
||||
fi
|
||||
AC_DEFINE(JS_SIMULATOR)
|
||||
AC_DEFINE(JS_SIMULATOR_ARM64)
|
||||
AC_DEFINE(JS_CODEGEN_ARM64)
|
||||
JS_SIMULATOR_ARM64=1
|
||||
JS_CODEGEN_ARM64=1
|
||||
elif test "$JS_SIMULATOR" = mips; then
|
||||
if test "$CPU_ARCH" != "x86"; then
|
||||
AC_MSG_ERROR([The MIPS simulator only works on x86.])
|
||||
fi
|
||||
AC_DEFINE(JS_MIPS_SIMULATOR)
|
||||
AC_DEFINE(JS_SIMULATOR)
|
||||
AC_DEFINE(JS_SIMULATOR_MIPS)
|
||||
AC_DEFINE(JS_CODEGEN_MIPS)
|
||||
JS_SIMULATOR_MIPS=1
|
||||
JS_CODEGEN_MIPS=1
|
||||
elif test "$CPU_ARCH" = "x86"; then
|
||||
AC_DEFINE(JS_CODEGEN_X86)
|
||||
@@ -3137,9 +3151,12 @@ elif test "$CPU_ARCH" = "mips"; then
|
||||
JS_CODEGEN_MIPS=1
|
||||
fi
|
||||
|
||||
AC_SUBST(JS_ARM_SIMULATOR)
|
||||
AC_SUBST(JS_MIPS_SIMULATOR)
|
||||
AC_SUBST(JS_SIMULATOR)
|
||||
AC_SUBST(JS_SIMULATOR_ARM)
|
||||
AC_SUBST(JS_SIMULATOR_ARM64)
|
||||
AC_SUBST(JS_SIMULATOR_MIPS)
|
||||
AC_SUBST(JS_CODEGEN_ARM)
|
||||
AC_SUBST(JS_CODEGEN_ARM64)
|
||||
AC_SUBST(JS_CODEGEN_MIPS)
|
||||
AC_SUBST(JS_CODEGEN_X86)
|
||||
AC_SUBST(JS_CODEGEN_X64)
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
--enable-debug
|
||||
--enable-stdcxx-compat
|
||||
--disable-shared-js
|
||||
--enable-arm-simulator
|
||||
--enable-simulator=arm
|
||||
--target=i686-pc-linux
|
||||
--host=i686-pc-linux
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
--enable-debug
|
||||
--enable-stdcxx-compat
|
||||
--disable-shared-js
|
||||
--enable-arm-simulator
|
||||
--enable-simulator=arm
|
||||
--target=i686-apple-darwin10.0.0
|
||||
--host=i686-apple-darwin10.0.0
|
||||
|
||||
@@ -13,7 +13,7 @@ var ignoreIndirectCalls = {
|
||||
"__conv" : true,
|
||||
"__convf" : true,
|
||||
"prerrortable.c:callback_newtable" : true,
|
||||
"mozalloc_oom.cpp:void (* gAbortHandler)(size_t)" : true
|
||||
"mozalloc_oom.cpp:void (* gAbortHandler)(size_t)" : true,
|
||||
};
|
||||
|
||||
function indirectCallCannotGC(fullCaller, fullVariable)
|
||||
@@ -180,8 +180,34 @@ var ignoreFunctions = {
|
||||
// analysis think maybe they can.
|
||||
"nsGlobalNameStruct* nsScriptNameSpaceManager::LookupNavigatorName(nsAString_internal*)": true,
|
||||
"nsGlobalNameStruct* nsScriptNameSpaceManager::LookupName(nsAString_internal*, uint16**)": true,
|
||||
|
||||
// Similar to heap snapshot mock classes, and GTests below. This posts a
|
||||
// synchronous runnable when a GTest fails, and we are pretty sure that the
|
||||
// particular runnable it posts can't even GC, but the analysis isn't
|
||||
// currently smart enough to determine that. In either case, this is (a)
|
||||
// only in GTests, and (b) only when the Gtest has already failed. We have
|
||||
// static and dynamic checks for no GC in the non-test code, and in the test
|
||||
// code we fall back to only the dynamic checks.
|
||||
"void test::RingbufferDumper::OnTestPartResult(testing::TestPartResult*)" : true,
|
||||
};
|
||||
|
||||
function isProtobuf(name)
|
||||
{
|
||||
return name.match(/\bgoogle::protobuf\b/) ||
|
||||
name.match(/\bmozilla::devtools::protobuf\b/);
|
||||
}
|
||||
|
||||
function isHeapSnapshotMockClass(name)
|
||||
{
|
||||
return name.match(/\bMockWriter\b/) ||
|
||||
name.match(/\bMockDeserializedNode\b/);
|
||||
}
|
||||
|
||||
function isGTest(name)
|
||||
{
|
||||
return name.match(/\btesting::/);
|
||||
}
|
||||
|
||||
function ignoreGCFunction(mangled)
|
||||
{
|
||||
assert(mangled in readableNames);
|
||||
@@ -190,6 +216,23 @@ function ignoreGCFunction(mangled)
|
||||
if (fun in ignoreFunctions)
|
||||
return true;
|
||||
|
||||
// The protobuf library, and [de]serialization code generated by the
|
||||
// protobuf compiler, uses a _ton_ of function pointers but they are all
|
||||
// internal. Easiest to just ignore that mess here.
|
||||
if (isProtobuf(fun))
|
||||
return true;
|
||||
|
||||
// Ignore anything that goes through heap snapshot GTests or mocked classes
|
||||
// used in heap snapshot GTests. GTest and GMock expose a lot of virtual
|
||||
// methods and function pointers that could potentially GC after an
|
||||
// assertion has already failed (depending on user-provided code), but don't
|
||||
// exhibit that behavior currently. For non-test code, we have dynamic and
|
||||
// static checks that ensure we don't GC. However, for test code we opt out
|
||||
// of static checks here, because of the above stated GMock/GTest issues,
|
||||
// and rely on only the dynamic checks provided by AutoAssertCannotGC.
|
||||
if (isHeapSnapshotMockClass(fun) || isGTest(fun))
|
||||
return true;
|
||||
|
||||
// Templatized function
|
||||
if (fun.indexOf("void nsCOMPtr<T>::Assert_NoQueryNeeded()") >= 0)
|
||||
return true;
|
||||
|
||||
@@ -44,6 +44,12 @@ js::CurrentThreadIsIonCompiling()
|
||||
return TlsPerThreadData.get()->ionCompiling;
|
||||
}
|
||||
|
||||
bool
|
||||
js::CurrentThreadIsIonCompilingSafeForMinorGC()
|
||||
{
|
||||
return TlsPerThreadData.get()->ionCompilingSafeForMinorGC;
|
||||
}
|
||||
|
||||
bool
|
||||
js::CurrentThreadIsGCSweeping()
|
||||
{
|
||||
|
||||
+3
-14
@@ -193,6 +193,9 @@ class JitCode;
|
||||
bool
|
||||
CurrentThreadIsIonCompiling();
|
||||
|
||||
bool
|
||||
CurrentThreadIsIonCompilingSafeForMinorGC();
|
||||
|
||||
bool
|
||||
CurrentThreadIsGCSweeping();
|
||||
|
||||
@@ -819,20 +822,6 @@ class HeapSlotArray
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Operations on a Heap thing inside the GC need to strip the barriers from
|
||||
* pointer operations. This template helps do that in contexts where the type
|
||||
* is templatized.
|
||||
*/
|
||||
template <typename T> struct Unbarriered {};
|
||||
template <typename S> struct Unbarriered< PreBarriered<S> > { typedef S* type; };
|
||||
template <typename S> struct Unbarriered< RelocatablePtr<S> > { typedef S* type; };
|
||||
template <> struct Unbarriered<PreBarrieredValue> { typedef Value type; };
|
||||
template <> struct Unbarriered<RelocatableValue> { typedef Value type; };
|
||||
template <typename S> struct Unbarriered< DefaultHasher< PreBarriered<S> > > {
|
||||
typedef DefaultHasher<S*> type;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* gc_Barrier_h */
|
||||
|
||||
+4
-1
@@ -1430,6 +1430,9 @@ TenuredCell::readBarrier(TenuredCell* thing)
|
||||
{
|
||||
MOZ_ASSERT(!CurrentThreadIsIonCompiling());
|
||||
MOZ_ASSERT(!isNullLike(thing));
|
||||
if (thing->shadowRuntimeFromAnyThread()->isHeapBusy())
|
||||
return;
|
||||
|
||||
JS::shadow::Zone* shadowZone = thing->shadowZoneFromAnyThread();
|
||||
if (shadowZone->needsIncrementalBarrier()) {
|
||||
MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));
|
||||
@@ -1445,7 +1448,7 @@ TenuredCell::readBarrier(TenuredCell* thing)
|
||||
TenuredCell::writeBarrierPre(TenuredCell* thing)
|
||||
{
|
||||
MOZ_ASSERT(!CurrentThreadIsIonCompiling());
|
||||
if (isNullLike(thing) || !thing->shadowRuntimeFromAnyThread()->needsIncrementalBarrier())
|
||||
if (isNullLike(thing) || thing->shadowRuntimeFromAnyThread()->isHeapBusy())
|
||||
return;
|
||||
|
||||
JS::shadow::Zone* shadowZone = thing->shadowZoneFromAnyThread();
|
||||
|
||||
+10
-10
@@ -1820,8 +1820,12 @@ js::gc::StoreBuffer::WholeCellEdges::trace(TenuringTracer& mover) const
|
||||
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(kind == JS::TraceKind::JitCode);
|
||||
static_cast<jit::JitCode*>(edge)->traceChildren(&mover);
|
||||
if (kind == JS::TraceKind::Script)
|
||||
static_cast<JSScript*>(edge)->traceChildren(&mover);
|
||||
else if (kind == JS::TraceKind::JitCode)
|
||||
static_cast<jit::JitCode*>(edge)->traceChildren(&mover);
|
||||
else
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1883,11 +1887,11 @@ js::Nursery::collectToFixedPoint(TenuringTracer& mover, TenureCountCache& tenure
|
||||
JSObject* obj = static_cast<JSObject*>(p->forwardingAddress());
|
||||
mover.traceObject(obj);
|
||||
|
||||
TenureCount& entry = tenureCounts.findEntry(obj->group());
|
||||
if (entry.group == obj->group()) {
|
||||
TenureCount& entry = tenureCounts.findEntry(obj->groupRaw());
|
||||
if (entry.group == obj->groupRaw()) {
|
||||
entry.count++;
|
||||
} else if (!entry.group) {
|
||||
entry.group = obj->group();
|
||||
entry.group = obj->groupRaw();
|
||||
entry.count = 1;
|
||||
}
|
||||
}
|
||||
@@ -2420,11 +2424,7 @@ js::UnmarkGrayCellRecursively(gc::Cell* cell, JS::TraceKind kind)
|
||||
MOZ_ASSERT(cell);
|
||||
|
||||
JSRuntime* rt = cell->runtimeFromMainThread();
|
||||
|
||||
// When the ReadBarriered type is used in a HashTable, it is difficult or
|
||||
// impossible to suppress the implicit cast operator while iterating for GC.
|
||||
if (rt->isHeapBusy())
|
||||
return false;
|
||||
MOZ_ASSERT(!rt->isHeapBusy());
|
||||
|
||||
bool unmarkedArg = false;
|
||||
if (cell->isTenured()) {
|
||||
|
||||
+10
-1
@@ -423,6 +423,14 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
|
||||
TenuringTracer mover(rt, this);
|
||||
|
||||
// Mark the store buffer. This must happen first.
|
||||
|
||||
TIME_START(cancelIonCompilations);
|
||||
if (sb.cancelIonCompilations()) {
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
|
||||
jit::StopAllOffThreadCompilations(c);
|
||||
}
|
||||
TIME_END(cancelIonCompilations);
|
||||
|
||||
TIME_START(traceValues);
|
||||
sb.traceValues(mover);
|
||||
TIME_END(traceValues);
|
||||
@@ -553,11 +561,12 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
|
||||
|
||||
#define FMT " %6" PRIu64
|
||||
fprintf(stderr,
|
||||
"MinorGC: %20s %5.1f%% %4d" FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT "\n",
|
||||
"MinorGC: %20s %5.1f%% %4d" FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT FMT "\n",
|
||||
js::gcstats::ExplainReason(reason),
|
||||
promotionRate * 100,
|
||||
numActiveChunks_,
|
||||
totalTime,
|
||||
TIME_TOTAL(cancelIonCompilations),
|
||||
TIME_TOTAL(traceValues),
|
||||
TIME_TOTAL(traceCells),
|
||||
TIME_TOTAL(traceSlots),
|
||||
|
||||
@@ -73,6 +73,7 @@ StoreBuffer::clear()
|
||||
return true;
|
||||
|
||||
aboutToOverflow_ = false;
|
||||
cancelIonCompilations_ = false;
|
||||
|
||||
bufferVal.clear();
|
||||
bufferCell.clear();
|
||||
|
||||
+10
-1
@@ -332,6 +332,8 @@ class StoreBuffer
|
||||
};
|
||||
|
||||
bool isOkayToUseBuffer() const {
|
||||
MOZ_ASSERT(!JS::shadow::Runtime::asShadowRuntime(runtime_)->isHeapBusy());
|
||||
|
||||
/*
|
||||
* Disabled store buffers may not have a valid state; e.g. when stored
|
||||
* inline in the ChunkTrailer.
|
||||
@@ -383,6 +385,7 @@ class StoreBuffer
|
||||
MonoTypeBuffer<ValueEdge> bufferRelocVal;
|
||||
MonoTypeBuffer<CellPtrEdge> bufferRelocCell;
|
||||
GenericBuffer bufferGeneric;
|
||||
bool cancelIonCompilations_;
|
||||
|
||||
JSRuntime* runtime_;
|
||||
const Nursery& nursery_;
|
||||
@@ -394,7 +397,7 @@ class StoreBuffer
|
||||
public:
|
||||
explicit StoreBuffer(JSRuntime* rt, const Nursery& nursery)
|
||||
: bufferVal(), bufferCell(), bufferSlot(), bufferWholeCell(),
|
||||
bufferRelocVal(), bufferRelocCell(), bufferGeneric(),
|
||||
bufferRelocVal(), bufferRelocCell(), bufferGeneric(), cancelIonCompilations_(false),
|
||||
runtime_(rt), nursery_(nursery), aboutToOverflow_(false), enabled_(false),
|
||||
mEntered(false)
|
||||
{
|
||||
@@ -409,6 +412,8 @@ class StoreBuffer
|
||||
/* Get the overflowed status. */
|
||||
bool isAboutToOverflow() const { return aboutToOverflow_; }
|
||||
|
||||
bool cancelIonCompilations() const { return cancelIonCompilations_; }
|
||||
|
||||
/* Insert a single edge into the buffer/remembered set. */
|
||||
void putValueFromAnyThread(JS::Value* valuep) { putFromAnyThread(bufferVal, ValueEdge(valuep)); }
|
||||
void putCellFromAnyThread(Cell** cellp) { putFromAnyThread(bufferCell, CellPtrEdge(cellp)); }
|
||||
@@ -444,6 +449,10 @@ class StoreBuffer
|
||||
putFromAnyThread(bufferGeneric, CallbackRef<Key>(callback, key, data));
|
||||
}
|
||||
|
||||
void setShouldCancelIonCompilations() {
|
||||
cancelIonCompilations_ = true;
|
||||
}
|
||||
|
||||
/* Methods to trace the source of all edges in the store buffer. */
|
||||
void traceValues(TenuringTracer& mover) { bufferVal.trace(this, mover); }
|
||||
void traceCells(TenuringTracer& mover) { bufferCell.trace(this, mover); }
|
||||
|
||||
@@ -442,6 +442,8 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
|
||||
writePerfSpewerJitCodeProfile(code, "RegExp");
|
||||
#endif
|
||||
|
||||
AutoWritableJitCode awjc(code);
|
||||
|
||||
for (size_t i = 0; i < labelPatches.length(); i++) {
|
||||
LabelPatch& v = labelPatches[i];
|
||||
MOZ_ASSERT(!v.label);
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
load(libdir + "class.js");
|
||||
|
||||
var test = `
|
||||
|
||||
function test(fun) {
|
||||
fun();
|
||||
}
|
||||
|
||||
// Generate a CallAnyScripted stub in test()
|
||||
for (let i = 0; i < 20; i++) {
|
||||
test(function() { /* wheeee */ });
|
||||
}
|
||||
|
||||
class foo {
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
// Compile foo()
|
||||
for (let i = 0; i < 11; i++)
|
||||
new foo();
|
||||
|
||||
try {
|
||||
test(foo);
|
||||
throw new Error("Invoking a class constructor without new must throw");
|
||||
} catch (e if e instanceof TypeError) { }
|
||||
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
eval(test);
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
function map_test(cases) {
|
||||
for (var i = 0; i < cases.length; i++) {
|
||||
var expected = cases[i].expected;
|
||||
}
|
||||
}
|
||||
map_test([{ input: 8, expected: 1114369}, { input: -1, expected: 0}]);
|
||||
map_test([{ expected: 16777215}, { expected: 4294967241 }]);
|
||||
@@ -1572,7 +1572,7 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIter
|
||||
bool overRecursed = false;
|
||||
BaselineBailoutInfo *info = builder.info();
|
||||
uint8_t* newsp = info->incomingStack - (info->copyStackTop - info->copyStackBottom);
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
if (Simulator::Current()->overRecursed(uintptr_t(newsp)))
|
||||
overRecursed = true;
|
||||
#else
|
||||
|
||||
@@ -226,7 +226,17 @@ BaselineCompiler::compile()
|
||||
// Adopt fallback stubs from the compiler into the baseline script.
|
||||
baselineScript->adoptFallbackStubs(&stubSpace_);
|
||||
|
||||
// Patch IC loads using IC entries
|
||||
// All barriers are emitted off-by-default, toggle them on if needed.
|
||||
if (cx->zone()->needsIncrementalBarrier())
|
||||
baselineScript->toggleBarriers(true);
|
||||
|
||||
// If profiler instrumentation is enabled, toggle instrumentation on.
|
||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
|
||||
baselineScript->toggleProfilerInstrumentation(true);
|
||||
|
||||
AutoWritableJitCode awjc(code);
|
||||
|
||||
// Patch IC loads using IC entries.
|
||||
for (size_t i = 0; i < icLoadLabels_.length(); i++) {
|
||||
CodeOffsetLabel label = icLoadLabels_[i].label;
|
||||
label.fixup(&masm);
|
||||
@@ -240,10 +250,6 @@ BaselineCompiler::compile()
|
||||
if (modifiesArguments_)
|
||||
baselineScript->setModifiesArguments();
|
||||
|
||||
// All barriers are emitted off-by-default, toggle them on if needed.
|
||||
if (cx->zone()->needsIncrementalBarrier())
|
||||
baselineScript->toggleBarriers(true);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
// Initialize the tracelogger instrumentation.
|
||||
baselineScript->initTraceLogger(cx->runtime(), script);
|
||||
@@ -261,10 +267,6 @@ BaselineCompiler::compile()
|
||||
if (compileDebugInstrumentation_)
|
||||
baselineScript->setHasDebugInstrumentation();
|
||||
|
||||
// If profiler instrumentation is enabled, toggle instrumentation on.
|
||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
|
||||
baselineScript->toggleProfilerInstrumentation(true);
|
||||
|
||||
// Always register a native => bytecode mapping entry, since profiler can be
|
||||
// turned on with baseline jitcode on stack, and baseline jitcode cannot be invalidated.
|
||||
{
|
||||
|
||||
@@ -9736,6 +9736,10 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||
if (constructing && !fun->isConstructor())
|
||||
return true;
|
||||
|
||||
// Likewise, if the callee is a class constructor, we have to throw.
|
||||
if (!constructing && fun->isClassConstructor())
|
||||
return true;
|
||||
|
||||
if (!fun->hasJITCode()) {
|
||||
// Don't treat this as an unoptimizable case, as we'll add a stub
|
||||
// when the callee becomes hot.
|
||||
@@ -10600,10 +10604,13 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
|
||||
// Ensure the object is a function.
|
||||
masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &JSFunction::class_,
|
||||
&failure);
|
||||
if (isConstructing_)
|
||||
if (isConstructing_) {
|
||||
masm.branchIfNotInterpretedConstructor(callee, regs.getAny(), &failure);
|
||||
else
|
||||
} else {
|
||||
masm.branchIfFunctionHasNoScript(callee, &failure);
|
||||
masm.branchFunctionKind(Assembler::Equal, JSFunction::ClassConstructor, callee,
|
||||
regs.getAny(), &failure);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the JSScript.
|
||||
@@ -11043,7 +11050,7 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
masm.passABIArg(argcReg);
|
||||
masm.passABIArg(vpReg);
|
||||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
// The simulator requires VM calls to be redirected to a special swi
|
||||
// instruction to handle them, so we store the redirected pointer in the
|
||||
// stub and use that instead of the original one.
|
||||
@@ -12681,7 +12688,7 @@ ICCall_Native::ICCall_Native(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
templateObject_(templateObject),
|
||||
pcOffset_(pcOffset)
|
||||
{
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
// The simulator requires VM calls to be redirected to a special swi
|
||||
// instruction to handle them. To make this work, we store the redirected
|
||||
// pointer in the stub.
|
||||
@@ -12707,7 +12714,7 @@ ICCall_ClassHook::ICCall_ClassHook(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
templateObject_(templateObject),
|
||||
pcOffset_(pcOffset)
|
||||
{
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
// The simulator requires VM calls to be redirected to a special swi
|
||||
// instruction to handle them. To make this work, we store the redirected
|
||||
// pointer in the stub.
|
||||
|
||||
@@ -4721,7 +4721,7 @@ class ICCall_Native : public ICMonitoredStub
|
||||
HeapPtrObject templateObject_;
|
||||
uint32_t pcOffset_;
|
||||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
void *native_;
|
||||
#endif
|
||||
|
||||
@@ -4747,7 +4747,7 @@ class ICCall_Native : public ICMonitoredStub
|
||||
return offsetof(ICCall_Native, pcOffset_);
|
||||
}
|
||||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_ARM64_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
static size_t offsetOfNative() {
|
||||
return offsetof(ICCall_Native, native_);
|
||||
}
|
||||
|
||||
@@ -859,6 +859,8 @@ BaselineScript::toggleDebugTraps(JSScript* script, jsbytecode* pc)
|
||||
|
||||
SrcNoteLineScanner scanner(script->notes(), script->lineno());
|
||||
|
||||
AutoWritableJitCode awjc(method());
|
||||
|
||||
for (uint32_t i = 0; i < numPCMappingIndexEntries(); i++) {
|
||||
PCMappingIndexEntry& entry = pcMappingIndexEntry(i);
|
||||
|
||||
@@ -905,6 +907,7 @@ BaselineScript::initTraceLogger(JSRuntime* runtime, JSScript* script)
|
||||
traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts);
|
||||
|
||||
if (TraceLogTextIdEnabled(TraceLogger_Engine) || TraceLogTextIdEnabled(TraceLogger_Scripts)) {
|
||||
AutoWritableJitCode awjc(method_);
|
||||
CodeLocationLabel enter(method_, CodeOffsetLabel(traceLoggerEnterToggleOffset_));
|
||||
CodeLocationLabel exit(method_, CodeOffsetLabel(traceLoggerExitToggleOffset_));
|
||||
Assembler::ToggleToCmp(enter);
|
||||
@@ -928,6 +931,8 @@ BaselineScript::toggleTraceLoggerScripts(JSRuntime* runtime, JSScript* script, b
|
||||
else
|
||||
traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts);
|
||||
|
||||
AutoWritableJitCode awjc(method());
|
||||
|
||||
// Enable/Disable the traceLogger prologue and epilogue.
|
||||
CodeLocationLabel enter(method_, CodeOffsetLabel(traceLoggerEnterToggleOffset_));
|
||||
CodeLocationLabel exit(method_, CodeOffsetLabel(traceLoggerExitToggleOffset_));
|
||||
@@ -954,6 +959,8 @@ BaselineScript::toggleTraceLoggerEngine(bool enable)
|
||||
MOZ_ASSERT(enable == !traceLoggerEngineEnabled_);
|
||||
MOZ_ASSERT(scriptsEnabled == traceLoggerScriptsEnabled_);
|
||||
|
||||
AutoWritableJitCode awjc(method());
|
||||
|
||||
// Enable/Disable the traceLogger prologue and epilogue.
|
||||
CodeLocationLabel enter(method_, CodeOffsetLabel(traceLoggerEnterToggleOffset_));
|
||||
CodeLocationLabel exit(method_, CodeOffsetLabel(traceLoggerExitToggleOffset_));
|
||||
@@ -982,6 +989,8 @@ BaselineScript::toggleProfilerInstrumentation(bool enable)
|
||||
JitSpew(JitSpew_BaselineIC, " toggling profiling %s for BaselineScript %p",
|
||||
enable ? "on" : "off", this);
|
||||
|
||||
AutoWritableJitCode awjc(method());
|
||||
|
||||
// Toggle the jump
|
||||
CodeLocationLabel enterToggleLocation(method_, CodeOffsetLabel(profilerEnterToggleOffset_));
|
||||
CodeLocationLabel exitToggleLocation(method_, CodeOffsetLabel(profilerExitToggleOffset_));
|
||||
|
||||
@@ -2235,19 +2235,6 @@ CodeGenerator::visitPointer(LPointer* lir)
|
||||
masm.movePtr(ImmPtr(lir->ptr()), ToRegister(lir->output()));
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitNurseryObject(LNurseryObject* lir)
|
||||
{
|
||||
Register output = ToRegister(lir->output());
|
||||
uint32_t index = lir->mir()->index();
|
||||
|
||||
// Store a dummy JSObject pointer. We will fix it up on the main thread,
|
||||
// in JitCode::fixupNurseryObjects. The low bit is set to distinguish
|
||||
// it from a real JSObject pointer.
|
||||
JSObject* ptr = reinterpret_cast<JSObject*>((uintptr_t(index) << 1) | 1);
|
||||
masm.movePtr(ImmGCPtr(IonNurseryPtr(ptr)), output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitKeepAliveObject(LKeepAliveObject* lir)
|
||||
{
|
||||
@@ -3041,10 +3028,12 @@ CodeGenerator::visitCallGeneric(LCallGeneric* call)
|
||||
|
||||
// Guard that calleereg is an interpreted function with a JSScript.
|
||||
// If we are constructing, also ensure the callee is a constructor.
|
||||
if (call->mir()->isConstructing())
|
||||
if (call->mir()->isConstructing()) {
|
||||
masm.branchIfNotInterpretedConstructor(calleereg, nargsreg, &invoke);
|
||||
else
|
||||
} else {
|
||||
masm.branchIfFunctionHasNoScript(calleereg, &invoke);
|
||||
masm.branchFunctionKind(Assembler::Equal, JSFunction::ClassConstructor, calleereg, objreg, &invoke);
|
||||
}
|
||||
|
||||
// Knowing that calleereg is a non-native function, load the JSScript.
|
||||
masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
|
||||
@@ -3138,6 +3127,7 @@ CodeGenerator::visitCallKnown(LCallKnown* call)
|
||||
|
||||
// Native single targets are handled by LCallNative.
|
||||
MOZ_ASSERT(!target->isNative());
|
||||
MOZ_ASSERT_IF(target->isClassConstructor(), call->isConstructing());
|
||||
// Missing arguments must have been explicitly appended by the IonBuilder.
|
||||
DebugOnly<unsigned> numNonArgsOnStack = 1 + call->isConstructing();
|
||||
MOZ_ASSERT(target->nargs() <= call->mir()->numStackArgs() - numNonArgsOnStack);
|
||||
@@ -3576,11 +3566,16 @@ CodeGenerator::generateArgumentsChecks(bool bailout)
|
||||
// Check for cases where the type set guard might have missed due to
|
||||
// changing object groups.
|
||||
for (uint32_t i = info.startArgSlot(); i < info.endArgSlot(); i++) {
|
||||
MParameter* param = rp->getOperand(i)->toParameter();
|
||||
const TemporaryTypeSet* types = param->resultTypeSet();
|
||||
if (!types || types->unknown())
|
||||
continue;
|
||||
|
||||
Label skip;
|
||||
Address addr(StackPointer, ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value)));
|
||||
masm.branchTestObject(Assembler::NotEqual, addr, &skip);
|
||||
Register obj = masm.extractObject(addr, temp);
|
||||
masm.guardTypeSetMightBeIncomplete(obj, temp, &success);
|
||||
masm.guardTypeSetMightBeIncomplete(types, obj, temp, &success);
|
||||
masm.bind(&skip);
|
||||
}
|
||||
|
||||
@@ -3810,7 +3805,7 @@ CodeGenerator::branchIfInvalidated(Register temp, Label* invalidated)
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, TemporaryTypeSet* typeset)
|
||||
CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, const TemporaryTypeSet* typeset)
|
||||
{
|
||||
MOZ_ASSERT(type == MIRType_Object || type == MIRType_ObjectOrNull ||
|
||||
type == MIRType_String || type == MIRType_Symbol);
|
||||
@@ -3840,7 +3835,7 @@ CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, Temp
|
||||
masm.jump(&ok);
|
||||
|
||||
masm.bind(&miss);
|
||||
masm.guardTypeSetMightBeIncomplete(input, temp, &ok);
|
||||
masm.guardTypeSetMightBeIncomplete(typeset, input, temp, &ok);
|
||||
|
||||
masm.assumeUnreachable("MIR instruction returned object with unexpected type");
|
||||
|
||||
@@ -3880,7 +3875,7 @@ CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, Temp
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::emitAssertResultV(const ValueOperand input, TemporaryTypeSet* typeset)
|
||||
CodeGenerator::emitAssertResultV(const ValueOperand input, const TemporaryTypeSet* typeset)
|
||||
{
|
||||
AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
|
||||
regs.take(input);
|
||||
@@ -3908,7 +3903,7 @@ CodeGenerator::emitAssertResultV(const ValueOperand input, TemporaryTypeSet* typ
|
||||
Label realMiss;
|
||||
masm.branchTestObject(Assembler::NotEqual, input, &realMiss);
|
||||
Register payload = masm.extractObject(input, temp1);
|
||||
masm.guardTypeSetMightBeIncomplete(payload, temp1, &ok);
|
||||
masm.guardTypeSetMightBeIncomplete(typeset, payload, temp1, &ok);
|
||||
masm.bind(&realMiss);
|
||||
|
||||
masm.assumeUnreachable("MIR instruction returned value with unexpected type");
|
||||
@@ -7957,10 +7952,43 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
|
||||
|
||||
script->setIonScript(cx, ionScript);
|
||||
|
||||
invalidateEpilogueData_.fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
|
||||
ImmPtr(ionScript),
|
||||
ImmPtr((void*)-1));
|
||||
{
|
||||
AutoWritableJitCode awjc(code);
|
||||
invalidateEpilogueData_.fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
|
||||
ImmPtr(ionScript),
|
||||
ImmPtr((void*)-1));
|
||||
|
||||
for (size_t i = 0; i < ionScriptLabels_.length(); i++) {
|
||||
ionScriptLabels_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, ionScriptLabels_[i]),
|
||||
ImmPtr(ionScript),
|
||||
ImmPtr((void*)-1));
|
||||
}
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
|
||||
for (uint32_t i = 0; i < patchableTraceLoggers_.length(); i++) {
|
||||
patchableTraceLoggers_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTraceLoggers_[i]),
|
||||
ImmPtr(logger),
|
||||
ImmPtr(nullptr));
|
||||
}
|
||||
|
||||
if (patchableTLScripts_.length() > 0) {
|
||||
MOZ_ASSERT(TraceLogTextIdEnabled(TraceLogger_Scripts));
|
||||
TraceLoggerEvent event(logger, TraceLogger_Scripts, script);
|
||||
ionScript->setTraceLoggerEvent(event);
|
||||
uint32_t textId = event.payload()->textId();
|
||||
for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
|
||||
patchableTLScripts_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
|
||||
ImmPtr((void*) uintptr_t(textId)),
|
||||
ImmPtr((void*)0));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JitSpew(JitSpew_Codegen, "Created IonScript %p (raw %p)",
|
||||
(void*) ionScript, (void*) code->raw());
|
||||
@@ -7978,13 +8006,6 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
|
||||
perfSpewer_.writeProfile(script, code, masm);
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < ionScriptLabels_.length(); i++) {
|
||||
ionScriptLabels_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, ionScriptLabels_[i]),
|
||||
ImmPtr(ionScript),
|
||||
ImmPtr((void*)-1));
|
||||
}
|
||||
|
||||
// for generating inline caches during the execution.
|
||||
if (runtimeData_.length())
|
||||
ionScript->copyRuntimeData(&runtimeData_[0]);
|
||||
@@ -8007,36 +8028,19 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
|
||||
MOZ_ASSERT_IF(snapshots_.listSize(), recovers_.size());
|
||||
if (recovers_.size())
|
||||
ionScript->copyRecovers(&recovers_);
|
||||
if (graph.numConstants())
|
||||
ionScript->copyConstants(graph.constantPool());
|
||||
if (patchableBackedges_.length() > 0)
|
||||
ionScript->copyPatchableBackedges(cx, code, patchableBackedges_.begin(), masm);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
|
||||
for (uint32_t i = 0; i < patchableTraceLoggers_.length(); i++) {
|
||||
patchableTraceLoggers_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTraceLoggers_[i]),
|
||||
ImmPtr(logger),
|
||||
ImmPtr(nullptr));
|
||||
}
|
||||
|
||||
if (patchableTLScripts_.length() > 0) {
|
||||
MOZ_ASSERT(TraceLogTextIdEnabled(TraceLogger_Scripts));
|
||||
TraceLoggerEvent event(logger, TraceLogger_Scripts, script);
|
||||
ionScript->setTraceLoggerEvent(event);
|
||||
uint32_t textId = event.payload()->textId();
|
||||
for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
|
||||
patchableTLScripts_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
|
||||
ImmPtr((void*) uintptr_t(textId)),
|
||||
ImmPtr((void*)0));
|
||||
if (graph.numConstants()) {
|
||||
const Value* vp = graph.constantPool();
|
||||
ionScript->copyConstants(vp);
|
||||
for (size_t i = 0; i < graph.numConstants(); i++) {
|
||||
const Value& v = vp[i];
|
||||
if (v.isObject() && IsInsideNursery(&v.toObject())) {
|
||||
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(script);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Replace dummy JSObject pointers embedded by LNurseryObject.
|
||||
code->fixupNurseryObjects(cx, gen->nurseryObjects());
|
||||
if (patchableBackedges_.length() > 0)
|
||||
ionScript->copyPatchableBackedges(cx, code, patchableBackedges_.begin(), masm);
|
||||
|
||||
// The correct state for prebarriers is unknown until the end of compilation,
|
||||
// since a GC can occur during code generation. All barriers are emitted
|
||||
|
||||
@@ -109,7 +109,6 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
void visitLambdaArrow(LLambdaArrow* lir);
|
||||
void visitLambdaForSingleton(LLambdaForSingleton* lir);
|
||||
void visitPointer(LPointer* lir);
|
||||
void visitNurseryObject(LNurseryObject* lir);
|
||||
void visitKeepAliveObject(LKeepAliveObject* lir);
|
||||
void visitSlots(LSlots* lir);
|
||||
void visitLoadSlotT(LLoadSlotT* lir);
|
||||
@@ -369,8 +368,8 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
|
||||
void visitAssertResultV(LAssertResultV* ins);
|
||||
void visitAssertResultT(LAssertResultT* ins);
|
||||
void emitAssertResultV(const ValueOperand output, TemporaryTypeSet* typeset);
|
||||
void emitAssertObjectOrStringResult(Register input, MIRType type, TemporaryTypeSet* typeset);
|
||||
void emitAssertResultV(const ValueOperand output, const TemporaryTypeSet* typeset);
|
||||
void emitAssertObjectOrStringResult(Register input, MIRType type, const TemporaryTypeSet* typeset);
|
||||
|
||||
void visitInterruptCheck(LInterruptCheck* lir);
|
||||
void visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir);
|
||||
|
||||
@@ -189,6 +189,13 @@ CompileRuntime::gcNursery()
|
||||
return runtime()->gc.nursery;
|
||||
}
|
||||
|
||||
void
|
||||
CompileRuntime::setMinorGCShouldCancelIonCompilations()
|
||||
{
|
||||
MOZ_ASSERT(onMainThread());
|
||||
runtime()->gc.storeBuffer.setShouldCancelIonCompilations();
|
||||
}
|
||||
|
||||
Zone*
|
||||
CompileZone::zone()
|
||||
{
|
||||
|
||||
@@ -85,6 +85,7 @@ class CompileRuntime
|
||||
const MathCache* maybeGetMathCache();
|
||||
|
||||
const Nursery& gcNursery();
|
||||
void setMinorGCShouldCancelIonCompilations();
|
||||
};
|
||||
|
||||
class CompileZone
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
|
||||
#include "js/MemoryMetrics.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
using namespace js::jit;
|
||||
|
||||
size_t ExecutableAllocator::pageSize = 0;
|
||||
@@ -62,3 +66,8 @@ ExecutableAllocator::addSizeOfCode(JS::CodeSizes* sizes) const
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
bool ExecutableAllocator::nonWritableJitCode = true;
|
||||
#else
|
||||
bool ExecutableAllocator::nonWritableJitCode = false;
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/*
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*
|
||||
* Copyright (C) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -53,18 +55,10 @@ extern "C" void sync_instruction_memory(caddr_t v, u_int len);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(JS_CODEGEN_MIPS) && defined(__linux__) && !defined(JS_MIPS_SIMULATOR)
|
||||
#if defined(JS_CODEGEN_MIPS) && defined(__linux__) && !defined(JS_SIMULATOR_MIPS)
|
||||
#include <sys/cachectl.h>
|
||||
#endif
|
||||
|
||||
#if ENABLE_ASSEMBLER_WX_EXCLUSIVE
|
||||
#define PROTECTION_FLAGS_RW (PROT_READ | PROT_WRITE)
|
||||
#define PROTECTION_FLAGS_RX (PROT_READ | PROT_EXEC)
|
||||
#define INITIAL_PROTECTION_FLAGS PROTECTION_FLAGS_RX
|
||||
#else
|
||||
#define INITIAL_PROTECTION_FLAGS (PROT_READ | PROT_WRITE | PROT_EXEC)
|
||||
#endif
|
||||
|
||||
namespace JS {
|
||||
struct CodeSizes;
|
||||
} // namespace JS
|
||||
@@ -177,12 +171,14 @@ namespace jit {
|
||||
}
|
||||
};
|
||||
|
||||
class ExecutableAllocator {
|
||||
class ExecutableAllocator
|
||||
{
|
||||
typedef void (*DestroyCallback)(void* addr, size_t size);
|
||||
enum ProtectionSetting { Writable, Executable };
|
||||
DestroyCallback destroyCallback;
|
||||
|
||||
public:
|
||||
enum ProtectionSetting { Writable, Executable };
|
||||
|
||||
ExecutableAllocator()
|
||||
: destroyCallback(nullptr)
|
||||
{
|
||||
@@ -267,6 +263,8 @@ class ExecutableAllocator {
|
||||
this->destroyCallback = destroyCallback;
|
||||
}
|
||||
|
||||
static bool nonWritableJitCode;
|
||||
|
||||
private:
|
||||
static size_t pageSize;
|
||||
static size_t largeAllocSize;
|
||||
@@ -380,27 +378,25 @@ class ExecutableAllocator {
|
||||
return pool;
|
||||
}
|
||||
|
||||
#if ENABLE_ASSEMBLER_WX_EXCLUSIVE
|
||||
static void makeWritable(void* start, size_t size)
|
||||
{
|
||||
reprotectRegion(start, size, Writable);
|
||||
if (nonWritableJitCode)
|
||||
reprotectRegion(start, size, Writable);
|
||||
}
|
||||
|
||||
static void makeExecutable(void* start, size_t size)
|
||||
{
|
||||
reprotectRegion(start, size, Executable);
|
||||
if (nonWritableJitCode)
|
||||
reprotectRegion(start, size, Executable);
|
||||
}
|
||||
#else
|
||||
static void makeWritable(void*, size_t) {}
|
||||
static void makeExecutable(void*, size_t) {}
|
||||
#endif
|
||||
|
||||
static unsigned initialProtectionFlags(ProtectionSetting protection);
|
||||
|
||||
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
|
||||
static void cacheFlush(void*, size_t)
|
||||
{
|
||||
}
|
||||
#elif defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#elif defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS)
|
||||
static void cacheFlush(void* code, size_t size)
|
||||
{
|
||||
js::jit::Simulator::FlushICache(code, size);
|
||||
@@ -447,9 +443,7 @@ class ExecutableAllocator {
|
||||
ExecutableAllocator(const ExecutableAllocator&) = delete;
|
||||
void operator=(const ExecutableAllocator&) = delete;
|
||||
|
||||
#if ENABLE_ASSEMBLER_WX_EXCLUSIVE
|
||||
static void reprotectRegion(void*, size_t, ProtectionSetting);
|
||||
#endif
|
||||
|
||||
// These are strong references; they keep pools alive.
|
||||
static const size_t maxSmallPools = 4;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/*
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*
|
||||
* Copyright (C) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -35,7 +37,8 @@
|
||||
|
||||
using namespace js::jit;
|
||||
|
||||
size_t ExecutableAllocator::determinePageSize()
|
||||
size_t
|
||||
ExecutableAllocator::determinePageSize()
|
||||
{
|
||||
return getpagesize();
|
||||
}
|
||||
@@ -57,24 +60,29 @@ js::jit::DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize)
|
||||
MOZ_ASSERT(!result || errno == ENOMEM);
|
||||
}
|
||||
|
||||
ExecutablePool::Allocation ExecutableAllocator::systemAlloc(size_t n)
|
||||
ExecutablePool::Allocation
|
||||
ExecutableAllocator::systemAlloc(size_t n)
|
||||
{
|
||||
void* allocation = AllocateExecutableMemory(nullptr, n, INITIAL_PROTECTION_FLAGS,
|
||||
void* allocation = AllocateExecutableMemory(nullptr, n, initialProtectionFlags(Executable),
|
||||
"js-jit-code", pageSize);
|
||||
ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
|
||||
return alloc;
|
||||
}
|
||||
|
||||
void ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
|
||||
void
|
||||
ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
|
||||
{
|
||||
DeallocateExecutableMemory(alloc.pages, alloc.size, pageSize);
|
||||
}
|
||||
|
||||
#if WTF_ENABLE_ASSEMBLER_WX_EXCLUSIVE
|
||||
void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting)
|
||||
static const unsigned FLAGS_RW = PROT_READ | PROT_WRITE;
|
||||
static const unsigned FLAGS_RX = PROT_READ | PROT_EXEC;
|
||||
|
||||
void
|
||||
ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting)
|
||||
{
|
||||
if (!pageSize)
|
||||
intializePageSize();
|
||||
MOZ_ASSERT(nonWritableJitCode);
|
||||
MOZ_ASSERT(pageSize);
|
||||
|
||||
// Calculate the start of the page containing this region,
|
||||
// and account for this extra memory within size.
|
||||
@@ -87,7 +95,14 @@ void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSe
|
||||
size += (pageSize - 1);
|
||||
size &= ~(pageSize - 1);
|
||||
|
||||
mprotect(pageStart, size, (setting == Writable) ? PROTECTION_FLAGS_RW : PROTECTION_FLAGS_RX);
|
||||
mprotect(pageStart, size, (setting == Writable) ? FLAGS_RW : FLAGS_RX);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */ unsigned
|
||||
ExecutableAllocator::initialProtectionFlags(ProtectionSetting protection)
|
||||
{
|
||||
if (!nonWritableJitCode)
|
||||
return FLAGS_RW | FLAGS_RX;
|
||||
|
||||
return (protection == Writable) ? FLAGS_RW : FLAGS_RX;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/*
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*
|
||||
* Copyright (C) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -35,14 +37,16 @@ using namespace js::jit;
|
||||
|
||||
uint64_t ExecutableAllocator::rngSeed;
|
||||
|
||||
size_t ExecutableAllocator::determinePageSize()
|
||||
size_t
|
||||
ExecutableAllocator::determinePageSize()
|
||||
{
|
||||
SYSTEM_INFO system_info;
|
||||
GetSystemInfo(&system_info);
|
||||
return system_info.dwPageSize;
|
||||
}
|
||||
|
||||
void* ExecutableAllocator::computeRandomAllocationAddress()
|
||||
void*
|
||||
ExecutableAllocator::computeRandomAllocationAddress()
|
||||
{
|
||||
/*
|
||||
* Inspiration is V8's OS::Allocate in platform-win32.cc.
|
||||
@@ -186,7 +190,6 @@ js::jit::AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions
|
||||
size_t pageSize)
|
||||
{
|
||||
MOZ_ASSERT(bytes % pageSize == 0);
|
||||
MOZ_ASSERT(permissions == PAGE_EXECUTE_READWRITE);
|
||||
|
||||
#ifdef JS_CPU_X64
|
||||
if (sJitExceptionHandler)
|
||||
@@ -226,31 +229,57 @@ js::jit::DeallocateExecutableMemory(void* addr, size_t bytes, size_t pageSize)
|
||||
VirtualFree(addr, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
ExecutablePool::Allocation ExecutableAllocator::systemAlloc(size_t n)
|
||||
ExecutablePool::Allocation
|
||||
ExecutableAllocator::systemAlloc(size_t n)
|
||||
{
|
||||
void* allocation = nullptr;
|
||||
// Randomization disabled to avoid a performance fault on x64 builds.
|
||||
// See bug 728623.
|
||||
#ifndef JS_CPU_X64
|
||||
if (!RandomizeIsBroken()) {
|
||||
void* randomAddress = computeRandomAllocationAddress();
|
||||
allocation = AllocateExecutableMemory(randomAddress, n, PAGE_EXECUTE_READWRITE,
|
||||
allocation = AllocateExecutableMemory(randomAddress, n, initialProtectionFlags(Executable),
|
||||
"js-jit-code", pageSize);
|
||||
}
|
||||
#endif
|
||||
if (!allocation) {
|
||||
allocation = AllocateExecutableMemory(nullptr, n, PAGE_EXECUTE_READWRITE,
|
||||
allocation = AllocateExecutableMemory(nullptr, n, initialProtectionFlags(Executable),
|
||||
"js-jit-code", pageSize);
|
||||
}
|
||||
ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
|
||||
return alloc;
|
||||
}
|
||||
|
||||
void ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
|
||||
void
|
||||
ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
|
||||
{
|
||||
DeallocateExecutableMemory(alloc.pages, alloc.size, pageSize);
|
||||
}
|
||||
|
||||
#if ENABLE_ASSEMBLER_WX_EXCLUSIVE
|
||||
#error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform."
|
||||
#endif
|
||||
void
|
||||
ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting)
|
||||
{
|
||||
MOZ_ASSERT(nonWritableJitCode);
|
||||
MOZ_ASSERT(pageSize);
|
||||
|
||||
// Calculate the start of the page containing this region,
|
||||
// and account for this extra memory within size.
|
||||
intptr_t startPtr = reinterpret_cast<intptr_t>(start);
|
||||
intptr_t pageStartPtr = startPtr & ~(pageSize - 1);
|
||||
void* pageStart = reinterpret_cast<void*>(pageStartPtr);
|
||||
size += (startPtr - pageStartPtr);
|
||||
|
||||
// Round size up
|
||||
size += (pageSize - 1);
|
||||
size &= ~(pageSize - 1);
|
||||
|
||||
DWORD oldProtect;
|
||||
int flags = (setting == Writable) ? PAGE_READWRITE : PAGE_EXECUTE_READ;
|
||||
if (!VirtualProtect(pageStart, size, flags, &oldProtect))
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
/* static */ unsigned
|
||||
ExecutableAllocator::initialProtectionFlags(ProtectionSetting protection)
|
||||
{
|
||||
if (!nonWritableJitCode)
|
||||
return PAGE_EXECUTE_READWRITE;
|
||||
|
||||
return (protection == Writable) ? PAGE_READWRITE : PAGE_EXECUTE_READ;
|
||||
}
|
||||
|
||||
+23
-87
@@ -168,8 +168,7 @@ JitRuntime::JitRuntime()
|
||||
osrTempData_(nullptr),
|
||||
mutatingBackedgeList_(false),
|
||||
ionReturnOverride_(MagicValue(JS_ARG_POISON)),
|
||||
jitcodeGlobalTable_(nullptr),
|
||||
hasIonNurseryObjects_(false)
|
||||
jitcodeGlobalTable_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -642,9 +641,10 @@ JitCompartment::mark(JSTracer* trc, JSCompartment* compartment)
|
||||
void
|
||||
JitCompartment::sweep(FreeOp* fop, JSCompartment* compartment)
|
||||
{
|
||||
// Cancel any active or pending off thread compilations. Note that the
|
||||
// MIR graph does not hold any nursery pointers, so there's no need to
|
||||
// do this for minor GCs.
|
||||
// Cancel any active or pending off thread compilations. The MIR graph only
|
||||
// contains nursery pointers if cancelIonCompilations() is set on the store
|
||||
// buffer, in which case store buffer marking will take care of this during
|
||||
// minor GCs.
|
||||
MOZ_ASSERT(!fop->runtime()->isHeapMinorCollecting());
|
||||
CancelOffThreadIonCompile(compartment, nullptr);
|
||||
FinishAllOffThreadCompilations(compartment);
|
||||
@@ -767,6 +767,12 @@ JitCode::traceChildren(JSTracer* trc)
|
||||
if (invalidated())
|
||||
return;
|
||||
|
||||
// If we're moving objects, we need writable JIT code.
|
||||
ReprotectCode reprotect = (trc->runtime()->isHeapMinorCollecting() || zone()->isGCCompacting())
|
||||
? Reprotect
|
||||
: DontReprotect;
|
||||
MaybeAutoWritableJitCode awjc(this, reprotect);
|
||||
|
||||
if (jumpRelocTableBytes_) {
|
||||
uint8_t* start = code_ + jumpRelocTableOffset();
|
||||
CompactBufferReader reader(start, start + jumpRelocTableBytes_);
|
||||
@@ -779,17 +785,6 @@ JitCode::traceChildren(JSTracer* trc)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JitCode::fixupNurseryObjects(JSContext* cx, const ObjectVector& nurseryObjects)
|
||||
{
|
||||
if (nurseryObjects.empty() || !dataRelocTableBytes_)
|
||||
return;
|
||||
|
||||
uint8_t* start = code_ + dataRelocTableOffset();
|
||||
CompactBufferReader reader(start, start + dataRelocTableBytes_);
|
||||
MacroAssembler::FixupNurseryObjects(cx, this, reader, nurseryObjects);
|
||||
}
|
||||
|
||||
void
|
||||
JitCode::finalize(FreeOp* fop)
|
||||
{
|
||||
@@ -806,8 +801,11 @@ JitCode::finalize(FreeOp* fop)
|
||||
// Buffer can be freed at any time hereafter. Catch use-after-free bugs.
|
||||
// Don't do this if the Ion code is protected, as the signal handler will
|
||||
// deadlock trying to reacquire the interrupt lock.
|
||||
memset(code_, JS_SWEPT_CODE_PATTERN, bufferSize_);
|
||||
code_ = nullptr;
|
||||
{
|
||||
AutoWritableJitCode awjc(this);
|
||||
memset(code_, JS_SWEPT_CODE_PATTERN, bufferSize_);
|
||||
code_ = nullptr;
|
||||
}
|
||||
|
||||
// Code buffers are stored inside JSC pools.
|
||||
// Pools are refcounted. Releasing the pool may free it.
|
||||
@@ -823,6 +821,7 @@ JitCode::finalize(FreeOp* fop)
|
||||
void
|
||||
JitCode::togglePreBarriers(bool enabled)
|
||||
{
|
||||
AutoWritableJitCode awjc(this);
|
||||
uint8_t* start = code_ + preBarrierTableOffset();
|
||||
CompactBufferReader reader(start, start + preBarrierTableBytes_);
|
||||
|
||||
@@ -1215,6 +1214,7 @@ IonScript::purgeCaches()
|
||||
if (invalidated())
|
||||
return;
|
||||
|
||||
AutoWritableJitCode awjc(method());
|
||||
for (size_t i = 0; i < numCaches(); i++)
|
||||
getCacheFromIndex(i).reset();
|
||||
}
|
||||
@@ -1711,7 +1711,7 @@ CodeGenerator*
|
||||
CompileBackEnd(MIRGenerator* mir)
|
||||
{
|
||||
// Everything in CompileBackEnd can potentially run on a helper thread.
|
||||
AutoEnterIonCompilation enter;
|
||||
AutoEnterIonCompilation enter(mir->safeForMinorGC());
|
||||
AutoSpewEndFunction spewEndFunction(mir);
|
||||
|
||||
if (!OptimizeMIR(mir))
|
||||
@@ -1840,65 +1840,6 @@ AttachFinishedCompilations(JSContext* cx)
|
||||
js_delete(debuggerAlloc);
|
||||
}
|
||||
|
||||
void
|
||||
MIRGenerator::traceNurseryObjects(JSTracer* trc)
|
||||
{
|
||||
TraceRootRange(trc, nurseryObjects_.length(), nurseryObjects_.begin(), "ion-nursery-objects");
|
||||
}
|
||||
|
||||
class MarkOffThreadNurseryObjects : public gc::BufferableRef
|
||||
{
|
||||
public:
|
||||
void trace(JSTracer* trc) override;
|
||||
};
|
||||
|
||||
void
|
||||
MarkOffThreadNurseryObjects::trace(JSTracer* trc)
|
||||
{
|
||||
JSRuntime* rt = trc->runtime();
|
||||
|
||||
if (trc->runtime()->isHeapMinorCollecting()) {
|
||||
// Only reset hasIonNurseryObjects if we're doing an actual minor GC.
|
||||
MOZ_ASSERT(rt->jitRuntime()->hasIonNurseryObjects());
|
||||
rt->jitRuntime()->setHasIonNurseryObjects(false);
|
||||
}
|
||||
|
||||
AutoLockHelperThreadState lock;
|
||||
if (!HelperThreadState().threads)
|
||||
return;
|
||||
|
||||
// Trace nursery objects of any builders which haven't started yet.
|
||||
GlobalHelperThreadState::IonBuilderVector& worklist = HelperThreadState().ionWorklist();
|
||||
for (size_t i = 0; i < worklist.length(); i++) {
|
||||
jit::IonBuilder* builder = worklist[i];
|
||||
if (builder->script()->runtimeFromAnyThread() == rt)
|
||||
builder->traceNurseryObjects(trc);
|
||||
}
|
||||
|
||||
// Trace nursery objects of in-progress entries.
|
||||
for (size_t i = 0; i < HelperThreadState().threadCount; i++) {
|
||||
HelperThread& helper = HelperThreadState().threads[i];
|
||||
if (helper.ionBuilder && helper.ionBuilder->script()->runtimeFromAnyThread() == rt)
|
||||
helper.ionBuilder->traceNurseryObjects(trc);
|
||||
}
|
||||
|
||||
// Trace nursery objects of any completed entries.
|
||||
GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList();
|
||||
for (size_t i = 0; i < finished.length(); i++) {
|
||||
jit::IonBuilder* builder = finished[i];
|
||||
if (builder->script()->runtimeFromAnyThread() == rt)
|
||||
builder->traceNurseryObjects(trc);
|
||||
}
|
||||
|
||||
// Trace nursery objects of lazy-linked builders.
|
||||
jit::IonBuilder* builder = HelperThreadState().ionLazyLinkList().getFirst();
|
||||
while (builder) {
|
||||
if (builder->script()->runtimeFromAnyThread() == rt)
|
||||
builder->traceNurseryObjects(trc);
|
||||
builder = builder->getNext();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TrackAllProperties(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
@@ -2032,6 +1973,9 @@ IonCompile(JSContext* cx, JSScript* script,
|
||||
if (!builder)
|
||||
return AbortReason_Alloc;
|
||||
|
||||
if (cx->runtime()->gc.storeBuffer.cancelIonCompilations())
|
||||
builder->setNotSafeForMinorGC();
|
||||
|
||||
MOZ_ASSERT(recompile == builder->script()->hasIonScript());
|
||||
MOZ_ASSERT(builder->script()->canIonCompile());
|
||||
|
||||
@@ -2089,15 +2033,6 @@ IonCompile(JSContext* cx, JSScript* script,
|
||||
". (Compiled on background thread.)",
|
||||
builderScript->filename(), builderScript->lineno());
|
||||
|
||||
JSRuntime* rt = cx->runtime();
|
||||
if (!builder->nurseryObjects().empty() && !rt->jitRuntime()->hasIonNurseryObjects()) {
|
||||
// Ensure the builder's nursery objects are marked when a nursery
|
||||
// GC happens on the main thread.
|
||||
MarkOffThreadNurseryObjects mark;
|
||||
rt->gc.storeBuffer.putGeneric(mark);
|
||||
rt->jitRuntime()->setHasIonNurseryObjects(true);
|
||||
}
|
||||
|
||||
if (!StartOffThreadIonCompile(cx, builder)) {
|
||||
JitSpew(JitSpew_IonAbort, "Unable to start off-thread ion compilation.");
|
||||
builder->graphSpewer().endFunction();
|
||||
@@ -2816,6 +2751,7 @@ InvalidateActivation(FreeOp* fop, const JitActivationIterator& activations, bool
|
||||
// the call sequence causing the safepoint being >= the size of
|
||||
// a uint32, which is checked during safepoint index
|
||||
// construction.
|
||||
AutoWritableJitCode awjc(ionCode);
|
||||
const SafepointIndex* si = ionScript->getSafepointIndex(it.returnAddressToFp());
|
||||
CodeLocationLabel dataLabelToMunge(it.returnAddressToFp());
|
||||
ptrdiff_t delta = ionScript->invalidateEpilogueDataOffset() -
|
||||
|
||||
+167
-191
@@ -235,39 +235,6 @@ IonBuilder::spew(const char* message)
|
||||
#endif
|
||||
}
|
||||
|
||||
MInstruction*
|
||||
IonBuilder::constantMaybeNursery(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(obj);
|
||||
if (!IsInsideNursery(obj))
|
||||
return constant(ObjectValue(*obj));
|
||||
|
||||
// If |obj| is in the nursery, we have to add it to the list of nursery
|
||||
// objects that get traced during off-thread compilation. We use
|
||||
// MNurseryObject to ensure we will patch the code with the right
|
||||
// pointer after codegen is done.
|
||||
|
||||
ObjectVector& nurseryObjects = outermostBuilder()->nurseryObjects_;
|
||||
|
||||
size_t index = UINT32_MAX;
|
||||
for (size_t i = 0, len = nurseryObjects.length(); i < len; i++) {
|
||||
if (nurseryObjects[i] == obj) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == UINT32_MAX) {
|
||||
if (!nurseryObjects.append(obj))
|
||||
return nullptr;
|
||||
index = nurseryObjects.length() - 1;
|
||||
}
|
||||
|
||||
MNurseryObject* ins = MNurseryObject::New(alloc(), obj, index, constraints());
|
||||
current->add(ins);
|
||||
return ins;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
GetJumpOffset(jsbytecode* pc)
|
||||
{
|
||||
@@ -474,6 +441,11 @@ IonBuilder::canInlineTarget(JSFunction* target, CallInfo& callInfo)
|
||||
return DontInline(inlineScript, "Callee is not a constructor");
|
||||
}
|
||||
|
||||
if (!callInfo.constructing() && target->isClassConstructor()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineClassConstructor);
|
||||
return DontInline(inlineScript, "Not constructing class constructor");
|
||||
}
|
||||
|
||||
AnalysisMode analysisMode = info().analysisMode();
|
||||
if (!CanIonCompile(inlineScript, analysisMode)) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineDisabledIon);
|
||||
@@ -979,6 +951,8 @@ IonBuilder::buildInline(IonBuilder* callerBuilder, MResumePoint* callerResumePoi
|
||||
if (callerBuilder->failedLexicalCheck_)
|
||||
failedLexicalCheck_ = true;
|
||||
|
||||
safeForMinorGC_ = callerBuilder->safeForMinorGC_;
|
||||
|
||||
// Generate single entrance block.
|
||||
if (!setCurrentAndSpecializePhis(newBlock(pc)))
|
||||
return false;
|
||||
@@ -4754,9 +4728,6 @@ IonBuilder::inlineScriptedCall(CallInfo& callInfo, JSFunction* target)
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(inlineBuilder.nurseryObjects_.empty(),
|
||||
"Nursery objects should be added to outer builder");
|
||||
|
||||
// Create return block.
|
||||
jsbytecode* postCall = GetNextPc(pc);
|
||||
MBasicBlock* returnBlock = newBlock(nullptr, postCall);
|
||||
@@ -5521,7 +5492,7 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const ObjectVector& targets, BoolVec
|
||||
// hoisting scope chain gets above the dispatch instruction.
|
||||
MInstruction* funcDef;
|
||||
if (target->isSingleton())
|
||||
funcDef = MConstant::New(alloc(), ObjectValue(*target), constraints());
|
||||
funcDef = MConstant::New(alloc(), ObjectValue(*target), constraints(), this);
|
||||
else
|
||||
funcDef = MPolyInlineGuard::New(alloc(), callInfo.fun());
|
||||
|
||||
@@ -5840,7 +5811,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction* target, MDefinition* callee)
|
||||
|
||||
// Generate an inline path to create a new |this| object with
|
||||
// the given singleton prototype.
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject, this);
|
||||
MCreateThisWithTemplate* createThis =
|
||||
MCreateThisWithTemplate::New(alloc(), constraints(), templateConst,
|
||||
templateObject->group()->initialHeap(constraints()));
|
||||
@@ -5871,7 +5842,7 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
|
||||
if (!protov.isObject())
|
||||
return nullptr;
|
||||
|
||||
JSObject* proto = &protov.toObject();
|
||||
JSObject* proto = checkNurseryObject(&protov.toObject());
|
||||
if (proto != templateObject->getProto())
|
||||
return nullptr;
|
||||
|
||||
@@ -5892,14 +5863,14 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
|
||||
current->add(slots);
|
||||
MLoadSlot* prototype = MLoadSlot::New(alloc(), slots, shape->slot());
|
||||
current->add(prototype);
|
||||
MDefinition* protoConst = constantMaybeNursery(proto);
|
||||
MDefinition* protoConst = constant(ObjectValue(*proto));
|
||||
MGuardObjectIdentity* guard = MGuardObjectIdentity::New(alloc(), prototype, protoConst,
|
||||
/* bailOnEquality = */ false);
|
||||
current->add(guard);
|
||||
|
||||
// Generate an inline path to create a new |this| object with
|
||||
// the given prototype.
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject, this);
|
||||
MCreateThisWithTemplate* createThis =
|
||||
MCreateThisWithTemplate::New(alloc(), constraints(), templateConst,
|
||||
templateObject->group()->initialHeap(constraints()));
|
||||
@@ -6513,7 +6484,7 @@ IonBuilder::jsop_newarray(uint32_t count)
|
||||
|
||||
if (templateObject) {
|
||||
heap = templateObject->group()->initialHeap(constraints());
|
||||
templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||
templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject, this);
|
||||
} else {
|
||||
heap = gc::DefaultHeap;
|
||||
templateConst = MConstant::New(alloc(), NullValue());
|
||||
@@ -6564,7 +6535,7 @@ IonBuilder::jsop_newobject()
|
||||
|
||||
if (templateObject) {
|
||||
heap = templateObject->group()->initialHeap(constraints());
|
||||
templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||
templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject, this);
|
||||
} else {
|
||||
heap = gc::DefaultHeap;
|
||||
templateConst = MConstant::New(alloc(), NullValue());
|
||||
@@ -7228,7 +7199,7 @@ IonBuilder::testSingletonProperty(JSObject* obj, PropertyName* name)
|
||||
if (ObjectHasExtraOwnProperty(compartment, objKey, name))
|
||||
return nullptr;
|
||||
|
||||
obj = obj->getProto();
|
||||
obj = checkNurseryObject(obj->getProto());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -7295,7 +7266,7 @@ IonBuilder::testSingletonPropertyTypes(MDefinition* obj, PropertyName* name)
|
||||
if (property.isOwnProperty(constraints()))
|
||||
return nullptr;
|
||||
|
||||
if (JSObject* proto = key->proto().toObjectOrNull()) {
|
||||
if (JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull())) {
|
||||
// Test this type.
|
||||
JSObject* thisSingleton = testSingletonProperty(proto, name);
|
||||
if (!thisSingleton)
|
||||
@@ -7644,17 +7615,13 @@ IonBuilder::jsop_getgname(PropertyName* name)
|
||||
if (!getStaticName(obj, name, &emitted) || emitted)
|
||||
return emitted;
|
||||
|
||||
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
|
||||
goto do_InlineCache;
|
||||
|
||||
{
|
||||
if (!forceInlineCaches()) {
|
||||
TemporaryTypeSet* types = bytecodeTypes(pc);
|
||||
MDefinition* globalObj = constant(ObjectValue(*obj));
|
||||
if (!getPropTryCommonGetter(&emitted, globalObj, name, types) || emitted)
|
||||
return emitted;
|
||||
}
|
||||
|
||||
do_InlineCache:
|
||||
return jsop_getname(name);
|
||||
}
|
||||
|
||||
@@ -7778,38 +7745,37 @@ IonBuilder::jsop_getelem()
|
||||
obj = maybeUnboxForPropertyAccess(obj);
|
||||
|
||||
bool emitted = false;
|
||||
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
|
||||
goto do_InlineCache;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_TypedObject);
|
||||
if (!getElemTryTypedObject(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
if (!forceInlineCaches()) {
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_TypedObject);
|
||||
if (!getElemTryTypedObject(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_Dense);
|
||||
if (!getElemTryDense(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_Dense);
|
||||
if (!getElemTryDense(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_TypedStatic);
|
||||
if (!getElemTryTypedStatic(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_TypedStatic);
|
||||
if (!getElemTryTypedStatic(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_TypedArray);
|
||||
if (!getElemTryTypedArray(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_TypedArray);
|
||||
if (!getElemTryTypedArray(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_String);
|
||||
if (!getElemTryString(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_String);
|
||||
if (!getElemTryString(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_Arguments);
|
||||
if (!getElemTryArguments(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_Arguments);
|
||||
if (!getElemTryArguments(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_ArgumentsInlined);
|
||||
if (!getElemTryArgumentsInlined(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
trackOptimizationAttempt(TrackedStrategy::GetElem_ArgumentsInlined);
|
||||
if (!getElemTryArgumentsInlined(&emitted, obj, index) || emitted)
|
||||
return emitted;
|
||||
}
|
||||
|
||||
do_InlineCache:
|
||||
if (script()->argumentsHasVarBinding() && obj->mightBeType(MIRType_MagicOptimizedArguments))
|
||||
return abort("Type is not definitely lazy arguments.");
|
||||
|
||||
@@ -8806,34 +8772,30 @@ IonBuilder::jsop_setelem()
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
|
||||
goto do_InlineCache;
|
||||
if (!forceInlineCaches()) {
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_TypedObject);
|
||||
if (!setElemTryTypedObject(&emitted, object, index, value) || emitted)
|
||||
return emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_TypedObject);
|
||||
if (!setElemTryTypedObject(&emitted, object, index, value) || emitted)
|
||||
return emitted;
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_TypedStatic);
|
||||
if (!setElemTryTypedStatic(&emitted, object, index, value) || emitted)
|
||||
return emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_TypedStatic);
|
||||
if (!setElemTryTypedStatic(&emitted, object, index, value) || emitted)
|
||||
return emitted;
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_TypedArray);
|
||||
if (!setElemTryTypedArray(&emitted, object, index, value) || emitted)
|
||||
return emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_TypedArray);
|
||||
if (!setElemTryTypedArray(&emitted, object, index, value) || emitted)
|
||||
return emitted;
|
||||
|
||||
{
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_Dense);
|
||||
SetElemICInspector icInspect(inspector->setElemICInspector(pc));
|
||||
bool writeHole = icInspect.sawOOBDenseWrite();
|
||||
if (!setElemTryDense(&emitted, object, index, value, writeHole) || emitted)
|
||||
return emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_Arguments);
|
||||
if (!setElemTryArguments(&emitted, object, index, value) || emitted)
|
||||
return emitted;
|
||||
}
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::SetElem_Arguments);
|
||||
if (!setElemTryArguments(&emitted, object, index, value) || emitted)
|
||||
return emitted;
|
||||
|
||||
do_InlineCache:
|
||||
if (script()->argumentsHasVarBinding() &&
|
||||
object->mightBeType(MIRType_MagicOptimizedArguments) &&
|
||||
info().analysisMode() != Analysis_ArgumentsUsage)
|
||||
@@ -9042,7 +9004,7 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object,
|
||||
}
|
||||
}
|
||||
|
||||
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
|
||||
if (PropertyWriteNeedsTypeBarrier(this, constraints(), current,
|
||||
&object, nullptr, &value, /* canModify = */ true))
|
||||
{
|
||||
trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
|
||||
@@ -9122,7 +9084,7 @@ IonBuilder::setElemTryCache(bool* emitted, MDefinition* object,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
|
||||
if (PropertyWriteNeedsTypeBarrier(this, constraints(), current,
|
||||
&object, nullptr, &value, /* canModify = */ true))
|
||||
{
|
||||
trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
|
||||
@@ -9472,7 +9434,7 @@ IonBuilder::jsop_rest()
|
||||
unsigned numFormals = info().nargs() - 1;
|
||||
unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
|
||||
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject, this);
|
||||
current->add(templateConst);
|
||||
|
||||
MNewArray* array = MNewArray::New(alloc(), constraints(), numRest, templateConst,
|
||||
@@ -9726,7 +9688,8 @@ IonBuilder::objectsHaveCommonPrototype(TemporaryTypeSet* types, PropertyName* na
|
||||
}
|
||||
}
|
||||
|
||||
JSObject* proto = key->proto().toObjectOrNull();
|
||||
JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull());
|
||||
|
||||
if (proto == foundProto)
|
||||
break;
|
||||
if (!proto) {
|
||||
@@ -9821,7 +9784,7 @@ IonBuilder::testCommonGetterSetter(TemporaryTypeSet* types, PropertyName* name,
|
||||
}
|
||||
}
|
||||
|
||||
MInstruction* wrapper = constantMaybeNursery(foundProto);
|
||||
MInstruction* wrapper = constant(ObjectValue(*foundProto));
|
||||
*guard = addShapeGuard(wrapper, lastProperty, Bailout_ShapeGuard);
|
||||
return true;
|
||||
}
|
||||
@@ -9871,6 +9834,7 @@ IonBuilder::annotateGetPropertyCache(MDefinition* obj, MGetPropertyCache* getPro
|
||||
TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(group);
|
||||
if (key->unknownProperties() || !key->proto().isObject())
|
||||
continue;
|
||||
JSObject* proto = checkNurseryObject(key->proto().toObject());
|
||||
|
||||
const Class* clasp = key->clasp();
|
||||
if (!ClassHasEffectlessLookup(clasp) || ObjectHasExtraOwnProperty(compartment, key, name))
|
||||
@@ -9880,7 +9844,7 @@ IonBuilder::annotateGetPropertyCache(MDefinition* obj, MGetPropertyCache* getPro
|
||||
if (ownTypes.isOwnProperty(constraints()))
|
||||
continue;
|
||||
|
||||
JSObject* singleton = testSingletonProperty(key->proto().toObject(), name);
|
||||
JSObject* singleton = testSingletonProperty(proto, name);
|
||||
if (!singleton || !singleton->is<JSFunction>())
|
||||
continue;
|
||||
|
||||
@@ -10124,45 +10088,43 @@ IonBuilder::jsop_getprop(PropertyName* name)
|
||||
if (!getPropTryInnerize(&emitted, obj, name, types) || emitted)
|
||||
return emitted;
|
||||
|
||||
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
|
||||
goto do_InlineCache;
|
||||
if (!forceInlineCaches()) {
|
||||
// Try to hardcode known constants.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
|
||||
if (!getPropTryConstant(&emitted, obj, name, types) || emitted)
|
||||
return emitted;
|
||||
|
||||
// Try to hardcode known constants.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
|
||||
if (!getPropTryConstant(&emitted, obj, name, types) || emitted)
|
||||
return emitted;
|
||||
// Try to emit SIMD getter loads
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_SimdGetter);
|
||||
if (!getPropTrySimdGetter(&emitted, obj, name) || emitted)
|
||||
return emitted;
|
||||
|
||||
// Try to emit SIMD getter loads
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_SimdGetter);
|
||||
if (!getPropTrySimdGetter(&emitted, obj, name) || emitted)
|
||||
return emitted;
|
||||
// Try to emit loads from known binary data blocks
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_TypedObject);
|
||||
if (!getPropTryTypedObject(&emitted, obj, name) || emitted)
|
||||
return emitted;
|
||||
|
||||
// Try to emit loads from known binary data blocks
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_TypedObject);
|
||||
if (!getPropTryTypedObject(&emitted, obj, name) || emitted)
|
||||
return emitted;
|
||||
// Try to emit loads from definite slots.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_DefiniteSlot);
|
||||
if (!getPropTryDefiniteSlot(&emitted, obj, name, barrier, types) || emitted)
|
||||
return emitted;
|
||||
|
||||
// Try to emit loads from definite slots.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_DefiniteSlot);
|
||||
if (!getPropTryDefiniteSlot(&emitted, obj, name, barrier, types) || emitted)
|
||||
return emitted;
|
||||
// Try to emit loads from unboxed objects.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_Unboxed);
|
||||
if (!getPropTryUnboxed(&emitted, obj, name, barrier, types) || emitted)
|
||||
return emitted;
|
||||
|
||||
// Try to emit loads from unboxed objects.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_Unboxed);
|
||||
if (!getPropTryUnboxed(&emitted, obj, name, barrier, types) || emitted)
|
||||
return emitted;
|
||||
// Try to inline a common property getter, or make a call.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter);
|
||||
if (!getPropTryCommonGetter(&emitted, obj, name, types) || emitted)
|
||||
return emitted;
|
||||
|
||||
// Try to inline a common property getter, or make a call.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter);
|
||||
if (!getPropTryCommonGetter(&emitted, obj, name, types) || emitted)
|
||||
return emitted;
|
||||
// Try to emit a monomorphic/polymorphic access based on baseline caches.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_InlineAccess);
|
||||
if (!getPropTryInlineAccess(&emitted, obj, name, barrier, types) || emitted)
|
||||
return emitted;
|
||||
}
|
||||
|
||||
// Try to emit a monomorphic/polymorphic access based on baseline caches.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_InlineAccess);
|
||||
if (!getPropTryInlineAccess(&emitted, obj, name, barrier, types) || emitted)
|
||||
return emitted;
|
||||
|
||||
do_InlineCache:
|
||||
// Try to emit a polymorphic cache.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_InlineCache);
|
||||
if (!getPropTryCache(&emitted, obj, name, barrier, types) || emitted)
|
||||
@@ -10718,7 +10680,7 @@ IonBuilder::addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Sh
|
||||
return addShapeGuard(obj, holderShape, Bailout_ShapeGuard);
|
||||
}
|
||||
|
||||
MDefinition* holderDef = constantMaybeNursery(holder);
|
||||
MDefinition* holderDef = constant(ObjectValue(*holder));
|
||||
addShapeGuard(holderDef, holderShape, Bailout_ShapeGuard);
|
||||
|
||||
return addGuardReceiverPolymorphic(obj, receivers);
|
||||
@@ -10812,7 +10774,7 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
|
||||
// Make sure there's enough room
|
||||
if (!current->ensureHasSlots(2))
|
||||
return false;
|
||||
current->push(constantMaybeNursery(commonGetter));
|
||||
current->push(constant(ObjectValue(*commonGetter)));
|
||||
|
||||
current->push(obj);
|
||||
|
||||
@@ -11053,7 +11015,7 @@ IonBuilder::getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name,
|
||||
// reflect such possible values.
|
||||
if (barrier != BarrierKind::TypeSet) {
|
||||
BarrierKind protoBarrier =
|
||||
PropertyReadOnPrototypeNeedsTypeBarrier(constraints(), obj, name, types);
|
||||
PropertyReadOnPrototypeNeedsTypeBarrier(this, constraints(), obj, name, types);
|
||||
if (protoBarrier != BarrierKind::NoBarrier) {
|
||||
MOZ_ASSERT(barrier <= protoBarrier);
|
||||
barrier = protoBarrier;
|
||||
@@ -11153,31 +11115,29 @@ IonBuilder::getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* na
|
||||
if (inner == obj)
|
||||
return true;
|
||||
|
||||
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
|
||||
goto do_InlineCache;
|
||||
if (!forceInlineCaches()) {
|
||||
// Note: the Baseline ICs don't know about this optimization, so it's
|
||||
// possible the global property's HeapTypeSet has not been initialized
|
||||
// yet. In this case we'll fall back to getPropTryCache for now.
|
||||
|
||||
// Note: the Baseline ICs don't know about this optimization, so it's
|
||||
// possible the global property's HeapTypeSet has not been initialized
|
||||
// yet. In this case we'll fall back to getPropTryCache for now.
|
||||
// Note that it's important that we do this _before_ we'd try to
|
||||
// do the optimizations below on obj normally, since some of those
|
||||
// optimizations have fallback paths that are slower than the path
|
||||
// we'd produce here.
|
||||
|
||||
// Note that it's important that we do this _before_ we'd try to
|
||||
// do the optimizations below on obj normally, since some of those
|
||||
// optimizations have fallback paths that are slower than the path
|
||||
// we'd produce here.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
|
||||
if (!getPropTryConstant(emitted, inner, name, types) || *emitted)
|
||||
return *emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
|
||||
if (!getPropTryConstant(emitted, inner, name, types) || *emitted)
|
||||
return *emitted;
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_StaticName);
|
||||
if (!getStaticName(&script()->global(), name, emitted) || *emitted)
|
||||
return *emitted;
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_StaticName);
|
||||
if (!getStaticName(&script()->global(), name, emitted) || *emitted)
|
||||
return *emitted;
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter);
|
||||
if (!getPropTryCommonGetter(emitted, inner, name, types) || *emitted)
|
||||
return *emitted;
|
||||
}
|
||||
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter);
|
||||
if (!getPropTryCommonGetter(emitted, inner, name, types) || *emitted)
|
||||
return *emitted;
|
||||
|
||||
do_InlineCache:
|
||||
// Passing the inner object to GetProperty IC is safe, see the
|
||||
// needsOuterizedThisObject check in IsCacheableGetPropCallNative.
|
||||
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
|
||||
@@ -11211,52 +11171,46 @@ IonBuilder::jsop_setprop(PropertyName* name)
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
|
||||
goto do_InlineCache_step1;
|
||||
if (!forceInlineCaches()) {
|
||||
// Try to inline a common property setter, or make a call.
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_CommonSetter);
|
||||
if (!setPropTryCommonSetter(&emitted, obj, name, value) || emitted)
|
||||
return emitted;
|
||||
|
||||
// Try to inline a common property setter, or make a call.
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_CommonSetter);
|
||||
if (!setPropTryCommonSetter(&emitted, obj, name, value) || emitted)
|
||||
return emitted;
|
||||
// Try to emit stores to known binary data blocks
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_TypedObject);
|
||||
if (!setPropTryTypedObject(&emitted, obj, name, value) || emitted)
|
||||
return emitted;
|
||||
}
|
||||
|
||||
// Try to emit stores to known binary data blocks
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_TypedObject);
|
||||
if (!setPropTryTypedObject(&emitted, obj, name, value) || emitted)
|
||||
return emitted;
|
||||
|
||||
do_InlineCache_step1:
|
||||
TemporaryTypeSet* objTypes = obj->resultTypeSet();
|
||||
bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, name, &value,
|
||||
bool barrier = PropertyWriteNeedsTypeBarrier(this, constraints(), current, &obj, name, &value,
|
||||
/* canModify = */ true);
|
||||
|
||||
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
|
||||
goto do_InlineCache_step2;
|
||||
if (!forceInlineCaches()) {
|
||||
// Try to emit stores to unboxed objects.
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_Unboxed);
|
||||
if (!setPropTryUnboxed(&emitted, obj, name, value, barrier, objTypes) || emitted)
|
||||
return emitted;
|
||||
}
|
||||
|
||||
// Try to emit stores to unboxed objects.
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_Unboxed);
|
||||
if (!setPropTryUnboxed(&emitted, obj, name, value, barrier, objTypes) || emitted)
|
||||
return emitted;
|
||||
|
||||
do_InlineCache_step2:
|
||||
// Add post barrier if needed. The instructions above manage any post
|
||||
// barriers they need directly.
|
||||
if (NeedsPostBarrier(info(), value))
|
||||
current->add(MPostWriteBarrier::New(alloc(), obj, value));
|
||||
|
||||
if (MOZ_UNLIKELY(js_JitOptions.forceInlineCaches))
|
||||
goto do_InlineCache_step3;
|
||||
if (!forceInlineCaches()) {
|
||||
// Try to emit store from definite slots.
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_DefiniteSlot);
|
||||
if (!setPropTryDefiniteSlot(&emitted, obj, name, value, barrier, objTypes) || emitted)
|
||||
return emitted;
|
||||
|
||||
// Try to emit store from definite slots.
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_DefiniteSlot);
|
||||
if (!setPropTryDefiniteSlot(&emitted, obj, name, value, barrier, objTypes) || emitted)
|
||||
return emitted;
|
||||
// Try to emit a monomorphic/polymorphic store based on baseline caches.
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_InlineAccess);
|
||||
if (!setPropTryInlineAccess(&emitted, obj, name, value, barrier, objTypes) || emitted)
|
||||
return emitted;
|
||||
}
|
||||
|
||||
// Try to emit a monomorphic/polymorphic store based on baseline caches.
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_InlineAccess);
|
||||
if (!setPropTryInlineAccess(&emitted, obj, name, value, barrier, objTypes) || emitted)
|
||||
return emitted;
|
||||
|
||||
do_InlineCache_step3:
|
||||
// Emit a polymorphic cache.
|
||||
trackOptimizationAttempt(TrackedStrategy::SetProp_InlineCache);
|
||||
return setPropTryCache(&emitted, obj, name, value, barrier, objTypes);
|
||||
@@ -11324,7 +11278,7 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj,
|
||||
if (!current->ensureHasSlots(3))
|
||||
return false;
|
||||
|
||||
current->push(constantMaybeNursery(commonSetter));
|
||||
current->push(constant(ObjectValue(*commonSetter)));
|
||||
current->push(obj);
|
||||
current->push(value);
|
||||
|
||||
@@ -11871,7 +11825,7 @@ IonBuilder::jsop_lambda(JSFunction* fun)
|
||||
if (fun->isNative() && IsAsmJSModuleNative(fun->native()))
|
||||
return abort("asm.js module function");
|
||||
|
||||
MConstant* cst = MConstant::NewConstraintlessObject(alloc(), fun);
|
||||
MConstant* cst = MConstant::NewConstraintlessObject(alloc(), fun, this);
|
||||
current->add(cst);
|
||||
MLambda* ins = MLambda::New(alloc(), constraints(), current->scopeChain(), cst);
|
||||
current->add(ins);
|
||||
@@ -12580,7 +12534,7 @@ IonBuilder::jsop_instanceof()
|
||||
current->add(slots);
|
||||
MLoadSlot* prototype = MLoadSlot::New(alloc(), slots, slot);
|
||||
current->add(prototype);
|
||||
MConstant* protoConst = MConstant::NewConstraintlessObject(alloc(), protoObject);
|
||||
MConstant* protoConst = MConstant::NewConstraintlessObject(alloc(), protoObject, this);
|
||||
current->add(protoConst);
|
||||
MGuardObjectIdentity* guard = MGuardObjectIdentity::New(alloc(), prototype, protoConst,
|
||||
/* bailOnEquality = */ false);
|
||||
@@ -12991,7 +12945,7 @@ IonBuilder::storeReferenceTypedObjectValue(MDefinition* typedObj,
|
||||
MIRType implicitType =
|
||||
(type == ReferenceTypeDescr::TYPE_ANY) ? MIRType_Undefined : MIRType_Null;
|
||||
|
||||
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &typedObj, name, &value,
|
||||
if (PropertyWriteNeedsTypeBarrier(this, constraints(), current, &typedObj, name, &value,
|
||||
/* canModify = */ true, implicitType))
|
||||
{
|
||||
trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
|
||||
@@ -13032,13 +12986,35 @@ IonBuilder::storeReferenceTypedObjectValue(MDefinition* typedObj,
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
IonBuilder::checkNurseryObject(JSObject* obj)
|
||||
{
|
||||
// If we try to use any nursery pointers during compilation, make sure that
|
||||
// the main thread will cancel this compilation before performing a minor
|
||||
// GC. All constants used during compilation should either go through this
|
||||
// function or should come from a type set (which has a similar barrier).
|
||||
if (obj && IsInsideNursery(obj)) {
|
||||
compartment->runtime()->setMinorGCShouldCancelIonCompilations();
|
||||
IonBuilder* builder = this;
|
||||
while (builder) {
|
||||
builder->setNotSafeForMinorGC();
|
||||
builder = builder->callerBuilder_;
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
MConstant*
|
||||
IonBuilder::constant(const Value& v)
|
||||
{
|
||||
MOZ_ASSERT(!v.isString() || v.toString()->isAtom(),
|
||||
"Handle non-atomized strings outside IonBuilder.");
|
||||
|
||||
MConstant* c = MConstant::New(alloc(), v, constraints());
|
||||
if (v.isObject())
|
||||
checkNurseryObject(&v.toObject());
|
||||
|
||||
MConstant* c = MConstant::New(alloc(), v, constraints(), this);
|
||||
current->add(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -228,8 +228,6 @@ class IonBuilder
|
||||
void trackActionableAbort(const char* message);
|
||||
void spew(const char* message);
|
||||
|
||||
MInstruction* constantMaybeNursery(JSObject* obj);
|
||||
|
||||
JSFunction* getSingleCallTarget(TemporaryTypeSet* calleeTypes);
|
||||
bool getPolyCallTargets(TemporaryTypeSet* calleeTypes, bool constructing,
|
||||
ObjectVector& targets, uint32_t maxTargets);
|
||||
@@ -981,6 +979,7 @@ class IonBuilder
|
||||
|
||||
public:
|
||||
void clearForBackEnd();
|
||||
JSObject* checkNurseryObject(JSObject* obj);
|
||||
|
||||
JSScript* script() const { return script_; }
|
||||
|
||||
@@ -1205,6 +1204,10 @@ class IonBuilder
|
||||
trackInlineSuccessUnchecked(status);
|
||||
}
|
||||
|
||||
bool forceInlineCaches() {
|
||||
return MOZ_UNLIKELY(js_JitOptions.forceInlineCaches);
|
||||
}
|
||||
|
||||
// Out-of-line variants that don't check if optimization tracking is
|
||||
// enabled.
|
||||
void trackTypeInfoUnchecked(JS::TrackedTypeSite site, MIRType mirType,
|
||||
|
||||
+19
-16
@@ -246,11 +246,13 @@ class IonCache::StubAttacher
|
||||
void patchRejoinJump(MacroAssembler& masm, JitCode* code) {
|
||||
rejoinOffset_.fixup(&masm);
|
||||
CodeLocationJump rejoinJump(code, rejoinOffset_);
|
||||
AutoWritableJitCode awjc(code);
|
||||
PatchJump(rejoinJump, rejoinLabel_);
|
||||
}
|
||||
|
||||
void patchStubCodePointer(MacroAssembler& masm, JitCode* code) {
|
||||
if (hasStubCodePatchOffset_) {
|
||||
AutoWritableJitCode awjc(code);
|
||||
stubCodePatchOffset_.fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, stubCodePatchOffset_),
|
||||
ImmPtr(code), STUB_ADDR);
|
||||
@@ -260,11 +262,12 @@ class IonCache::StubAttacher
|
||||
void patchNextStubJump(MacroAssembler& masm, JitCode* code) {
|
||||
// Patch the previous nextStubJump of the last stub, or the jump from the
|
||||
// codeGen, to jump into the newly allocated code.
|
||||
PatchJump(cache_.lastJump_, CodeLocationLabel(code));
|
||||
PatchJump(cache_.lastJump_, CodeLocationLabel(code), Reprotect);
|
||||
|
||||
// If this path is not taken, we are producing an entry which can no
|
||||
// longer go back into the update function.
|
||||
if (hasNextStubOffset_) {
|
||||
AutoWritableJitCode awjc(code);
|
||||
nextStubOffset_.fixup(&masm);
|
||||
CodeLocationJump nextStubJump(code, nextStubOffset_);
|
||||
PatchJump(nextStubJump, cache_.fallbackLabel_);
|
||||
@@ -371,6 +374,7 @@ IonCache::linkAndAttachStub(JSContext* cx, MacroAssembler& masm, StubAttacher& a
|
||||
void
|
||||
IonCache::updateBaseAddress(JitCode* code, MacroAssembler& masm)
|
||||
{
|
||||
AutoWritableJitCode awjc(code);
|
||||
fallbackLabel_.repoint(code, &masm);
|
||||
initialJump_.repoint(code, &masm);
|
||||
lastJump_.repoint(code, &masm);
|
||||
@@ -410,8 +414,7 @@ GeneratePrototypeGuards(JSContext* cx, IonScript* ion, MacroAssembler& masm, JSO
|
||||
// use objectReg in the rest of this function.
|
||||
masm.loadPtr(Address(objectReg, JSObject::offsetOfGroup()), scratchReg);
|
||||
Address proto(scratchReg, ObjectGroup::offsetOfProto());
|
||||
masm.branchPtr(Assembler::NotEqual, proto,
|
||||
ImmMaybeNurseryPtr(obj->getProto()), failures);
|
||||
masm.branchPtr(Assembler::NotEqual, proto, ImmGCPtr(obj->getProto()), failures);
|
||||
}
|
||||
|
||||
JSObject* pobj = IsCacheableDOMProxy(obj)
|
||||
@@ -422,7 +425,7 @@ GeneratePrototypeGuards(JSContext* cx, IonScript* ion, MacroAssembler& masm, JSO
|
||||
while (pobj != holder) {
|
||||
if (pobj->hasUncacheableProto()) {
|
||||
MOZ_ASSERT(!pobj->isSingleton());
|
||||
masm.movePtr(ImmMaybeNurseryPtr(pobj), scratchReg);
|
||||
masm.movePtr(ImmGCPtr(pobj), scratchReg);
|
||||
Address groupAddr(scratchReg, JSObject::offsetOfGroup());
|
||||
masm.branchPtr(Assembler::NotEqual, groupAddr, ImmGCPtr(pobj->group()), failures);
|
||||
}
|
||||
@@ -801,7 +804,7 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
||||
if (holder) {
|
||||
// Guard on the holder's shape.
|
||||
holderReg = scratchReg;
|
||||
masm.movePtr(ImmMaybeNurseryPtr(holder), holderReg);
|
||||
masm.movePtr(ImmGCPtr(holder), holderReg);
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(holderReg, JSObject::offsetOfShape()),
|
||||
ImmGCPtr(holder->as<NativeObject>().lastProperty()),
|
||||
@@ -983,7 +986,7 @@ EmitGetterCall(JSContext* cx, MacroAssembler& masm,
|
||||
} else {
|
||||
// If the holder is on the prototype chain, the prototype-guarding
|
||||
// only allows objects with the same holder.
|
||||
masm.movePtr(ImmMaybeNurseryPtr(holder), scratchReg);
|
||||
masm.movePtr(ImmGCPtr(holder), scratchReg);
|
||||
masm.Push(scratchReg);
|
||||
}
|
||||
masm.moveStackPtrTo(argObjReg);
|
||||
@@ -1036,7 +1039,7 @@ EmitGetterCall(JSContext* cx, MacroAssembler& masm,
|
||||
masm.Push(UndefinedValue());
|
||||
masm.Push(TypedOrValueRegister(MIRType_Object, AnyRegister(object)));
|
||||
|
||||
masm.movePtr(ImmMaybeNurseryPtr(target), scratchReg);
|
||||
masm.movePtr(ImmGCPtr(target), scratchReg);
|
||||
|
||||
descriptor = MakeFrameDescriptor(argSize + padding, JitFrame_IonAccessorIC);
|
||||
masm.Push(Imm32(0)); // argc
|
||||
@@ -1093,7 +1096,7 @@ GenerateCallGetter(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
||||
|
||||
// Guard on the holder's shape.
|
||||
Register holderReg = scratchReg;
|
||||
masm.movePtr(ImmMaybeNurseryPtr(holder), holderReg);
|
||||
masm.movePtr(ImmGCPtr(holder), holderReg);
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(holderReg, JSObject::offsetOfShape()),
|
||||
ImmGCPtr(holder->as<NativeObject>().lastProperty()),
|
||||
@@ -1696,7 +1699,7 @@ GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext* cx, HandleScript outerScri
|
||||
Register holderReg = scratchReg;
|
||||
|
||||
// Guard on the holder of the property
|
||||
masm.movePtr(ImmMaybeNurseryPtr(holder), holderReg);
|
||||
masm.movePtr(ImmGCPtr(holder), holderReg);
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(holderReg, JSObject::offsetOfShape()),
|
||||
ImmGCPtr(holder->lastProperty()),
|
||||
@@ -2006,8 +2009,9 @@ GetPropertyIC::reset()
|
||||
}
|
||||
|
||||
void
|
||||
IonCache::disable()
|
||||
IonCache::disable(IonScript* ion)
|
||||
{
|
||||
AutoWritableJitCode awjc(ion->method());
|
||||
reset();
|
||||
this->disabled_ = 1;
|
||||
}
|
||||
@@ -2419,7 +2423,7 @@ GenerateCallSetter(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
||||
if (obj != holder)
|
||||
GeneratePrototypeGuards(cx, ion, masm, obj, holder, object, scratchReg, &protoFailure);
|
||||
|
||||
masm.movePtr(ImmMaybeNurseryPtr(holder), scratchReg);
|
||||
masm.movePtr(ImmGCPtr(holder), scratchReg);
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(scratchReg, JSObject::offsetOfShape()),
|
||||
ImmGCPtr(holder->as<NativeObject>().lastProperty()),
|
||||
@@ -2604,7 +2608,7 @@ GenerateCallSetter(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
||||
masm.Push(value);
|
||||
masm.Push(TypedOrValueRegister(MIRType_Object, AnyRegister(object)));
|
||||
|
||||
masm.movePtr(ImmMaybeNurseryPtr(target), scratchReg);
|
||||
masm.movePtr(ImmGCPtr(target), scratchReg);
|
||||
|
||||
descriptor = MakeFrameDescriptor(argSize + padding, JitFrame_IonAccessorIC);
|
||||
masm.Push(Imm32(1)); // argc
|
||||
@@ -3517,15 +3521,14 @@ GenerateDenseElementHole(JSContext* cx, MacroAssembler& masm, IonCache::StubAtta
|
||||
if (obj->hasUncacheableProto()) {
|
||||
masm.loadPtr(Address(object, JSObject::offsetOfGroup()), scratchReg);
|
||||
Address proto(scratchReg, ObjectGroup::offsetOfProto());
|
||||
masm.branchPtr(Assembler::NotEqual, proto,
|
||||
ImmMaybeNurseryPtr(obj->getProto()), &failures);
|
||||
masm.branchPtr(Assembler::NotEqual, proto, ImmGCPtr(obj->getProto()), &failures);
|
||||
}
|
||||
|
||||
JSObject* pobj = obj->getProto();
|
||||
while (pobj) {
|
||||
MOZ_ASSERT(pobj->as<NativeObject>().lastProperty());
|
||||
|
||||
masm.movePtr(ImmMaybeNurseryPtr(pobj), scratchReg);
|
||||
masm.movePtr(ImmGCPtr(pobj), scratchReg);
|
||||
if (pobj->hasUncacheableProto()) {
|
||||
MOZ_ASSERT(!pobj->isSingleton());
|
||||
Address groupAddr(scratchReg, JSObject::offsetOfGroup());
|
||||
@@ -4054,7 +4057,7 @@ GetElementIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex,
|
||||
cache.incFailedUpdates();
|
||||
if (cache.shouldDisable()) {
|
||||
JitSpew(JitSpew_IonIC, "Disable inline cache");
|
||||
cache.disable();
|
||||
cache.disable(ion);
|
||||
}
|
||||
} else {
|
||||
cache.resetFailedUpdates();
|
||||
|
||||
@@ -243,7 +243,7 @@ class IonCache
|
||||
{
|
||||
}
|
||||
|
||||
virtual void disable();
|
||||
void disable(IonScript* ion);
|
||||
inline bool isDisabled() const {
|
||||
return disabled_;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,10 @@ class JitCode : public gc::TenuredCell
|
||||
size_t instructionsSize() const {
|
||||
return insnSize_;
|
||||
}
|
||||
size_t bufferSize() const {
|
||||
return bufferSize_;
|
||||
}
|
||||
|
||||
void traceChildren(JSTracer* trc);
|
||||
void finalize(FreeOp* fop);
|
||||
void fixupAfterMovingGC() {}
|
||||
@@ -110,8 +114,6 @@ class JitCode : public gc::TenuredCell
|
||||
invalidated_ = true;
|
||||
}
|
||||
|
||||
void fixupNurseryObjects(JSContext* cx, const ObjectVector& nurseryObjects);
|
||||
|
||||
void setHasBytecodeMap() {
|
||||
hasBytecodeMap_ = true;
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
|
||||
// Various macros used by all JITs.
|
||||
|
||||
#if defined(JS_ARM_SIMULATOR)
|
||||
#if defined(JS_SIMULATOR_ARM)
|
||||
#include "jit/arm/Simulator-arm.h"
|
||||
#elif defined(JS_MIPS_SIMULATOR)
|
||||
#elif defined(JS_SIMULATOR_MIPS)
|
||||
#include "jit/mips/Simulator-mips.h"
|
||||
#endif
|
||||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS)
|
||||
// Call into cross-jitted code by following the ABI of the simulated architecture.
|
||||
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
|
||||
(js::jit::Simulator::Current()->call( \
|
||||
|
||||
@@ -228,8 +228,6 @@ class JitRuntime
|
||||
// Global table of jitcode native address => bytecode address mappings.
|
||||
JitcodeGlobalTable* jitcodeGlobalTable_;
|
||||
|
||||
bool hasIonNurseryObjects_;
|
||||
|
||||
private:
|
||||
JitCode* generateLazyLinkStub(JSContext* cx);
|
||||
JitCode* generateProfilerExitFrameTailStub(JSContext* cx);
|
||||
@@ -376,13 +374,6 @@ class JitRuntime
|
||||
ionReturnOverride_ = v;
|
||||
}
|
||||
|
||||
bool hasIonNurseryObjects() const {
|
||||
return hasIonNurseryObjects_;
|
||||
}
|
||||
void setHasIonNurseryObjects(bool b) {
|
||||
hasIonNurseryObjects_ = b;
|
||||
}
|
||||
|
||||
bool hasJitcodeGlobalTable() const {
|
||||
return jitcodeGlobalTable_ != nullptr;
|
||||
}
|
||||
@@ -557,6 +548,51 @@ void FinishInvalidation(FreeOp* fop, JSScript* script);
|
||||
const unsigned WINDOWS_BIG_FRAME_TOUCH_INCREMENT = 4096 - 1;
|
||||
#endif
|
||||
|
||||
// If ExecutableAllocator::nonWritableJitCode is |true|, this class will ensure
|
||||
// JIT code is writable (has RW permissions) in its scope. If nonWritableJitCode
|
||||
// is |false|, it's a no-op.
|
||||
class MOZ_STACK_CLASS AutoWritableJitCode
|
||||
{
|
||||
JSRuntime* rt_;
|
||||
void* addr_;
|
||||
size_t size_;
|
||||
|
||||
public:
|
||||
AutoWritableJitCode(JSRuntime* rt, void* addr, size_t size)
|
||||
: rt_(rt), addr_(addr), size_(size)
|
||||
{
|
||||
rt_->toggleAutoWritableJitCodeActive(true);
|
||||
ExecutableAllocator::makeWritable(addr_, size_);
|
||||
}
|
||||
AutoWritableJitCode(void* addr, size_t size)
|
||||
: AutoWritableJitCode(TlsPerThreadData.get()->runtimeFromMainThread(), addr, size)
|
||||
{}
|
||||
explicit AutoWritableJitCode(JitCode* code)
|
||||
: AutoWritableJitCode(code->runtimeFromMainThread(), code->raw(), code->bufferSize())
|
||||
{}
|
||||
~AutoWritableJitCode() {
|
||||
ExecutableAllocator::makeExecutable(addr_, size_);
|
||||
rt_->toggleAutoWritableJitCodeActive(false);
|
||||
}
|
||||
};
|
||||
|
||||
enum ReprotectCode { Reprotect = true, DontReprotect = false };
|
||||
|
||||
class MOZ_STACK_CLASS MaybeAutoWritableJitCode
|
||||
{
|
||||
mozilla::Maybe<AutoWritableJitCode> awjc_;
|
||||
|
||||
public:
|
||||
MaybeAutoWritableJitCode(void* addr, size_t size, ReprotectCode reprotect) {
|
||||
if (reprotect)
|
||||
awjc_.emplace(addr, size);
|
||||
}
|
||||
MaybeAutoWritableJitCode(JitCode* code, ReprotectCode reprotect) {
|
||||
if (reprotect)
|
||||
awjc_.emplace(code);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
||||
@@ -712,16 +712,6 @@ class LValue : public LInstructionHelper<BOX_PIECES, 0, 0>
|
||||
}
|
||||
};
|
||||
|
||||
class LNurseryObject : public LInstructionHelper<1, 0, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(NurseryObject);
|
||||
|
||||
MNurseryObject* mir() const {
|
||||
return mir_->toNurseryObject();
|
||||
}
|
||||
};
|
||||
|
||||
// Clone an object literal such as we are not modifying the object contained in
|
||||
// the sources.
|
||||
class LCloneLiteral : public LCallInstructionHelper<1, 1, 0>
|
||||
|
||||
@@ -347,7 +347,6 @@
|
||||
_(AssertResultT) \
|
||||
_(LexicalCheck) \
|
||||
_(ThrowUninitializedLexical) \
|
||||
_(NurseryObject) \
|
||||
_(Debugger) \
|
||||
_(NewTarget) \
|
||||
_(ArrowNewTarget)
|
||||
|
||||
@@ -68,6 +68,7 @@ class Linker
|
||||
return nullptr;
|
||||
if (masm.oom())
|
||||
return fail(cx);
|
||||
AutoWritableJitCode awjc(result, bytesNeeded);
|
||||
code->copyFrom(masm);
|
||||
masm.link(code);
|
||||
if (masm.embedsNurseryPointers())
|
||||
|
||||
+10
-9
@@ -456,7 +456,7 @@ LIRGenerator::visitCall(MCall* call)
|
||||
MOZ_ASSERT(ok, "How can we not have four temp registers?");
|
||||
lir = new(alloc()) LCallDOMNative(tempFixed(cxReg), tempFixed(objReg),
|
||||
tempFixed(privReg), tempFixed(argsReg));
|
||||
} else if (target) {
|
||||
} else if (target && !(target->isClassConstructor() && !call->isConstructing())) {
|
||||
// Call known functions.
|
||||
if (target->isNative()) {
|
||||
Register cxReg, numReg, vpReg, tmpReg;
|
||||
@@ -2226,11 +2226,18 @@ void
|
||||
LIRGenerator::visitInterruptCheck(MInterruptCheck* ins)
|
||||
{
|
||||
// Implicit interrupt checks require asm.js signal handlers to be installed.
|
||||
// They also require writable JIT code: reprotecting in patchIonBackedges
|
||||
// would be expensive and using AutoWritableJitCode in the signal handler
|
||||
// is complicated because there could be another AutoWritableJitCode on the
|
||||
// stack.
|
||||
LInstructionHelper<0, 0, 0>* lir;
|
||||
if (GetJitContext()->runtime->canUseSignalHandlers())
|
||||
if (GetJitContext()->runtime->canUseSignalHandlers() &&
|
||||
!ExecutableAllocator::nonWritableJitCode)
|
||||
{
|
||||
lir = new(alloc()) LInterruptCheckImplicit();
|
||||
else
|
||||
} else {
|
||||
lir = new(alloc()) LInterruptCheck();
|
||||
}
|
||||
add(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
@@ -4176,12 +4183,6 @@ LIRGenerator::visitDebugger(MDebugger* ins)
|
||||
add(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitNurseryObject(MNurseryObject* ins)
|
||||
{
|
||||
define(new(alloc()) LNurseryObject(), ins);
|
||||
}
|
||||
|
||||
static void
|
||||
SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
|
||||
{
|
||||
|
||||
@@ -295,7 +295,6 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
void visitLexicalCheck(MLexicalCheck* ins);
|
||||
void visitThrowUninitializedLexical(MThrowUninitializedLexical* ins);
|
||||
void visitDebugger(MDebugger* ins);
|
||||
void visitNurseryObject(MNurseryObject* ins);
|
||||
void visitNewTarget(MNewTarget* ins);
|
||||
void visitArrowNewTarget(MArrowNewTarget* ins);
|
||||
};
|
||||
|
||||
@@ -583,7 +583,7 @@ IonBuilder::inlineArray(CallInfo& callInfo)
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject, this);
|
||||
current->add(templateConst);
|
||||
|
||||
MNewArray* ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
|
||||
@@ -758,7 +758,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
|
||||
|
||||
MDefinition* obj = callInfo.thisArg();
|
||||
MDefinition* value = callInfo.getArg(0);
|
||||
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
|
||||
if (PropertyWriteNeedsTypeBarrier(this, constraints(), current,
|
||||
&obj, nullptr, &value, /* canModify = */ false))
|
||||
{
|
||||
trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
|
||||
@@ -1009,6 +1009,16 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
|
||||
if (!templateObj)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (unboxedType == JSVAL_TYPE_MAGIC) {
|
||||
if (!templateObj->is<ArrayObject>())
|
||||
return InliningStatus_NotInlined;
|
||||
} else {
|
||||
if (!templateObj->is<UnboxedArrayObject>())
|
||||
return InliningStatus_NotInlined;
|
||||
if (templateObj->as<UnboxedArrayObject>().elementType() != unboxedType)
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MDefinition* begin;
|
||||
@@ -1679,7 +1689,7 @@ IonBuilder::inlineConstantStringSplit(CallInfo& callInfo)
|
||||
if (conversion == TemporaryTypeSet::AlwaysConvertToDoubles)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject, this);
|
||||
current->add(templateConst);
|
||||
|
||||
MNewArray* ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
|
||||
@@ -1749,7 +1759,8 @@ IonBuilder::inlineStringSplit(CallInfo& callInfo)
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
MConstant* templateObjectDef = MConstant::New(alloc(), ObjectValue(*templateObject), constraints());
|
||||
MConstant* templateObjectDef = MConstant::New(alloc(), ObjectValue(*templateObject),
|
||||
constraints(), this);
|
||||
current->add(templateObjectDef);
|
||||
|
||||
MStringSplit* ins = MStringSplit::New(alloc(), constraints(), callInfo.thisArg(),
|
||||
@@ -2074,7 +2085,7 @@ IonBuilder::inlineObjectCreate(CallInfo& callInfo)
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject, this);
|
||||
current->add(templateConst);
|
||||
MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst,
|
||||
templateObject->group()->initialHeap(constraints()),
|
||||
|
||||
+33
-59
@@ -625,17 +625,20 @@ MDefinition::emptyResultTypeSet() const
|
||||
}
|
||||
|
||||
MConstant*
|
||||
MConstant::New(TempAllocator& alloc, const Value& v, CompilerConstraintList* constraints)
|
||||
MConstant::New(TempAllocator& alloc, const Value& v,
|
||||
CompilerConstraintList* constraints, MIRGenerator* gen)
|
||||
{
|
||||
return new(alloc) MConstant(v, constraints);
|
||||
return new(alloc) MConstant(v, constraints, gen);
|
||||
}
|
||||
|
||||
MConstant*
|
||||
MConstant::NewTypedValue(TempAllocator& alloc, const Value& v, MIRType type, CompilerConstraintList* constraints)
|
||||
MConstant::NewTypedValue(TempAllocator& alloc, const Value& v, MIRType type,
|
||||
CompilerConstraintList* constraints, MIRGenerator* gen)
|
||||
{
|
||||
MOZ_ASSERT(!IsSimdType(type));
|
||||
MOZ_ASSERT_IF(type == MIRType_Float32, IsNaN(v.toDouble()) || v.toDouble() == double(float(v.toDouble())));
|
||||
MConstant* constant = new(alloc) MConstant(v, constraints);
|
||||
MOZ_ASSERT_IF(type == MIRType_Float32,
|
||||
IsNaN(v.toDouble()) || v.toDouble() == double(float(v.toDouble())));
|
||||
MConstant* constant = new(alloc) MConstant(v, constraints, gen);
|
||||
constant->setResultType(type);
|
||||
return constant;
|
||||
}
|
||||
@@ -649,9 +652,9 @@ MConstant::NewAsmJS(TempAllocator& alloc, const Value& v, MIRType type)
|
||||
}
|
||||
|
||||
MConstant*
|
||||
MConstant::NewConstraintlessObject(TempAllocator& alloc, JSObject* v)
|
||||
MConstant::NewConstraintlessObject(TempAllocator& alloc, JSObject* v, MIRGenerator* gen)
|
||||
{
|
||||
return new(alloc) MConstant(v);
|
||||
return new(alloc) MConstant(v, gen);
|
||||
}
|
||||
|
||||
static TemporaryTypeSet*
|
||||
@@ -707,14 +710,15 @@ jit::IonCompilationCanUseNurseryPointers()
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
MConstant::MConstant(const js::Value& vp, CompilerConstraintList* constraints)
|
||||
MConstant::MConstant(const js::Value& vp, CompilerConstraintList* constraints, MIRGenerator* gen)
|
||||
: value_(vp)
|
||||
{
|
||||
setResultType(MIRTypeFromValue(vp));
|
||||
if (vp.isObject()) {
|
||||
// Create a singleton type set for the object. This isn't necessary for
|
||||
// other types as the result type encodes all needed information.
|
||||
MOZ_ASSERT(!IsInsideNursery(&vp.toObject()));
|
||||
MOZ_ASSERT(gen);
|
||||
MOZ_ASSERT_IF(IsInsideNursery(&vp.toObject()), !gen->safeForMinorGC());
|
||||
setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject()));
|
||||
}
|
||||
if (vp.isMagic() && vp.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
|
||||
@@ -733,10 +737,11 @@ MConstant::MConstant(const js::Value& vp, CompilerConstraintList* constraints)
|
||||
setMovable();
|
||||
}
|
||||
|
||||
MConstant::MConstant(JSObject* obj)
|
||||
MConstant::MConstant(JSObject* obj, MIRGenerator* gen)
|
||||
: value_(ObjectValue(*obj))
|
||||
{
|
||||
MOZ_ASSERT(!IsInsideNursery(obj));
|
||||
MOZ_ASSERT(gen);
|
||||
MOZ_ASSERT_IF(IsInsideNursery(obj), !gen->safeForMinorGC());
|
||||
setResultType(MIRType_Object);
|
||||
setMovable();
|
||||
}
|
||||
@@ -779,12 +784,12 @@ MConstant::printOpcode(GenericPrinter& out) const
|
||||
out.printf("0x%x", value().toInt32());
|
||||
break;
|
||||
case MIRType_Double:
|
||||
out.printf("%f", value().toDouble());
|
||||
out.printf("%.16g", value().toDouble());
|
||||
break;
|
||||
case MIRType_Float32:
|
||||
{
|
||||
float val = value().toDouble();
|
||||
out.printf("%f", val);
|
||||
out.printf("%.16g", val);
|
||||
break;
|
||||
}
|
||||
case MIRType_Object:
|
||||
@@ -846,39 +851,6 @@ MConstant::canProduceFloat32() const
|
||||
return true;
|
||||
}
|
||||
|
||||
MNurseryObject::MNurseryObject(JSObject* obj, uint32_t index, CompilerConstraintList* constraints)
|
||||
: index_(index)
|
||||
{
|
||||
setResultType(MIRType_Object);
|
||||
|
||||
MOZ_ASSERT(IsInsideNursery(obj));
|
||||
MOZ_ASSERT(!obj->isSingleton());
|
||||
setResultTypeSet(MakeSingletonTypeSet(constraints, obj));
|
||||
|
||||
setMovable();
|
||||
}
|
||||
|
||||
MNurseryObject*
|
||||
MNurseryObject::New(TempAllocator& alloc, JSObject* obj, uint32_t index,
|
||||
CompilerConstraintList* constraints)
|
||||
{
|
||||
return new(alloc) MNurseryObject(obj, index, constraints);
|
||||
}
|
||||
|
||||
HashNumber
|
||||
MNurseryObject::valueHash() const
|
||||
{
|
||||
return HashNumber(index_);
|
||||
}
|
||||
|
||||
bool
|
||||
MNurseryObject::congruentTo(const MDefinition* ins) const
|
||||
{
|
||||
if (!ins->isNurseryObject())
|
||||
return false;
|
||||
return ins->toNurseryObject()->index_ == index_;
|
||||
}
|
||||
|
||||
MDefinition*
|
||||
MSimdValueX4::foldsTo(TempAllocator& alloc)
|
||||
{
|
||||
@@ -5002,7 +4974,8 @@ jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
|
||||
}
|
||||
|
||||
BarrierKind
|
||||
jit::PropertyReadOnPrototypeNeedsTypeBarrier(CompilerConstraintList* constraints,
|
||||
jit::PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
|
||||
CompilerConstraintList* constraints,
|
||||
MDefinition* obj, PropertyName* name,
|
||||
TemporaryTypeSet* observed)
|
||||
{
|
||||
@@ -5024,7 +4997,8 @@ jit::PropertyReadOnPrototypeNeedsTypeBarrier(CompilerConstraintList* constraints
|
||||
return BarrierKind::TypeSet;
|
||||
if (!key->proto().isObject())
|
||||
break;
|
||||
key = TypeSet::ObjectKey::get(key->proto().toObject());
|
||||
JSObject* proto = builder->checkNurseryObject(key->proto().toObject());
|
||||
key = TypeSet::ObjectKey::get(proto);
|
||||
BarrierKind kind = PropertyReadNeedsTypeBarrier(constraints, key, name, observed);
|
||||
if (kind == BarrierKind::TypeSet)
|
||||
return BarrierKind::TypeSet;
|
||||
@@ -5216,18 +5190,18 @@ TryAddTypeBarrierForWrite(TempAllocator& alloc, CompilerConstraintList* constrai
|
||||
}
|
||||
|
||||
static MInstruction*
|
||||
AddGroupGuard(TempAllocator& alloc, MBasicBlock* current, MDefinition* obj,
|
||||
AddGroupGuard(MIRGenerator* gen, MBasicBlock* current, MDefinition* obj,
|
||||
TypeSet::ObjectKey* key, bool bailOnEquality)
|
||||
{
|
||||
MInstruction* guard;
|
||||
|
||||
if (key->isGroup()) {
|
||||
guard = MGuardObjectGroup::New(alloc, obj, key->group(), bailOnEquality,
|
||||
guard = MGuardObjectGroup::New(gen->alloc(), obj, key->group(), bailOnEquality,
|
||||
Bailout_ObjectIdentityOrTypeGuard);
|
||||
} else {
|
||||
MConstant* singletonConst = MConstant::NewConstraintlessObject(alloc, key->singleton());
|
||||
MConstant* singletonConst = MConstant::NewConstraintlessObject(gen->alloc(), key->singleton(), gen);
|
||||
current->add(singletonConst);
|
||||
guard = MGuardObjectIdentity::New(alloc, obj, singletonConst, bailOnEquality);
|
||||
guard = MGuardObjectIdentity::New(gen->alloc(), obj, singletonConst, bailOnEquality);
|
||||
}
|
||||
|
||||
current->add(guard);
|
||||
@@ -5250,7 +5224,7 @@ jit::CanWriteProperty(TempAllocator& alloc, CompilerConstraintList* constraints,
|
||||
}
|
||||
|
||||
bool
|
||||
jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* constraints,
|
||||
jit::PropertyWriteNeedsTypeBarrier(MIRGenerator* gen, CompilerConstraintList* constraints,
|
||||
MBasicBlock* current, MDefinition** pobj,
|
||||
PropertyName* name, MDefinition** pvalue,
|
||||
bool canModify, MIRType implicitType)
|
||||
@@ -5285,14 +5259,14 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
HeapTypeSetKey property = key->property(id);
|
||||
if (!CanWriteProperty(alloc, constraints, property, *pvalue, implicitType)) {
|
||||
if (!CanWriteProperty(gen->alloc(), constraints, property, *pvalue, implicitType)) {
|
||||
// Either pobj or pvalue needs to be modified to filter out the
|
||||
// types which the value could have but are not in the property,
|
||||
// or a VM call is required. A VM call is always required if pobj
|
||||
// and pvalue cannot be modified.
|
||||
if (!canModify)
|
||||
return true;
|
||||
success = TryAddTypeBarrierForWrite(alloc, constraints, current, types, name, pvalue,
|
||||
success = TryAddTypeBarrierForWrite(gen->alloc(), constraints, current, types, name, pvalue,
|
||||
implicitType);
|
||||
break;
|
||||
}
|
||||
@@ -5306,10 +5280,10 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
|
||||
const UnboxedLayout& layout = key->group()->unboxedLayout();
|
||||
if (name) {
|
||||
const UnboxedLayout::Property* property = layout.lookup(name);
|
||||
if (property && !CanStoreUnboxedType(alloc, property->type, *pvalue))
|
||||
if (property && !CanStoreUnboxedType(gen->alloc(), property->type, *pvalue))
|
||||
return true;
|
||||
} else {
|
||||
if (layout.isArray() && !CanStoreUnboxedType(alloc, layout.elementType(), *pvalue))
|
||||
if (layout.isArray() && !CanStoreUnboxedType(gen->alloc(), layout.elementType(), *pvalue))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -5338,7 +5312,7 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
HeapTypeSetKey property = key->property(id);
|
||||
if (CanWriteProperty(alloc, constraints, property, *pvalue, implicitType))
|
||||
if (CanWriteProperty(gen->alloc(), constraints, property, *pvalue, implicitType))
|
||||
continue;
|
||||
|
||||
if ((property.maybeTypes() && !property.maybeTypes()->empty()) || excluded)
|
||||
@@ -5359,6 +5333,6 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
|
||||
}
|
||||
}
|
||||
|
||||
*pobj = AddGroupGuard(alloc, current, *pobj, excluded, /* bailOnEquality = */ true);
|
||||
*pobj = AddGroupGuard(gen, current, *pobj, excluded, /* bailOnEquality = */ true);
|
||||
return false;
|
||||
}
|
||||
|
||||
+11
-34
@@ -1304,17 +1304,20 @@ class MConstant : public MNullaryInstruction
|
||||
Value value_;
|
||||
|
||||
protected:
|
||||
MConstant(const Value& v, CompilerConstraintList* constraints);
|
||||
explicit MConstant(JSObject* obj);
|
||||
MConstant(const Value& v, CompilerConstraintList* constraints, MIRGenerator* gen);
|
||||
explicit MConstant(JSObject* obj, MIRGenerator* gen);
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(Constant)
|
||||
static MConstant* New(TempAllocator& alloc, const Value& v,
|
||||
CompilerConstraintList* constraints = nullptr);
|
||||
CompilerConstraintList* constraints = nullptr,
|
||||
MIRGenerator* gen = nullptr);
|
||||
static MConstant* NewTypedValue(TempAllocator& alloc, const Value& v, MIRType type,
|
||||
CompilerConstraintList* constraints = nullptr);
|
||||
CompilerConstraintList* constraints = nullptr,
|
||||
MIRGenerator* gen = nullptr);
|
||||
static MConstant* NewAsmJS(TempAllocator& alloc, const Value& v, MIRType type);
|
||||
static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v);
|
||||
static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v,
|
||||
MIRGenerator* gen);
|
||||
|
||||
const js::Value& value() const {
|
||||
return value_;
|
||||
@@ -1356,33 +1359,6 @@ class MConstant : public MNullaryInstruction
|
||||
ALLOW_CLONE(MConstant)
|
||||
};
|
||||
|
||||
class MNurseryObject : public MNullaryInstruction
|
||||
{
|
||||
// Index in MIRGenerator::nurseryObjects_.
|
||||
uint32_t index_;
|
||||
|
||||
protected:
|
||||
MNurseryObject(JSObject* obj, uint32_t index, CompilerConstraintList* constraints);
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(NurseryObject)
|
||||
static MNurseryObject* New(TempAllocator& alloc, JSObject* obj, uint32_t index,
|
||||
CompilerConstraintList* constraints = nullptr);
|
||||
|
||||
HashNumber valueHash() const override;
|
||||
bool congruentTo(const MDefinition* ins) const override;
|
||||
|
||||
uint32_t index() const {
|
||||
return index_;
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
||||
ALLOW_CLONE(MNurseryObject)
|
||||
};
|
||||
|
||||
// Generic constructor of SIMD valuesX4.
|
||||
class MSimdValueX4
|
||||
: public MQuaternaryInstruction,
|
||||
@@ -13581,7 +13557,8 @@ BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
|
||||
CompilerConstraintList* constraints,
|
||||
MDefinition* obj, PropertyName* name,
|
||||
TemporaryTypeSet* observed);
|
||||
BarrierKind PropertyReadOnPrototypeNeedsTypeBarrier(CompilerConstraintList* constraints,
|
||||
BarrierKind PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
|
||||
CompilerConstraintList* constraints,
|
||||
MDefinition* obj, PropertyName* name,
|
||||
TemporaryTypeSet* observed);
|
||||
bool PropertyReadIsIdempotent(CompilerConstraintList* constraints,
|
||||
@@ -13591,7 +13568,7 @@ void AddObjectsForPropertyRead(MDefinition* obj, PropertyName* name,
|
||||
bool CanWriteProperty(TempAllocator& alloc, CompilerConstraintList* constraints,
|
||||
HeapTypeSetKey property, MDefinition* value,
|
||||
MIRType implicitType = MIRType_None);
|
||||
bool PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* constraints,
|
||||
bool PropertyWriteNeedsTypeBarrier(MIRGenerator* gen, CompilerConstraintList* constraints,
|
||||
MBasicBlock* current, MDefinition** pobj,
|
||||
PropertyName* name, MDefinition** pvalue,
|
||||
bool canModify, MIRType implicitType = MIRType_None);
|
||||
|
||||
@@ -94,6 +94,13 @@ class MIRGenerator
|
||||
return isProfilerInstrumentationEnabled() && !info().isAnalysis();
|
||||
}
|
||||
|
||||
bool safeForMinorGC() const {
|
||||
return safeForMinorGC_;
|
||||
}
|
||||
void setNotSafeForMinorGC() {
|
||||
safeForMinorGC_ = false;
|
||||
}
|
||||
|
||||
// Whether the main thread is trying to cancel this build.
|
||||
bool shouldCancel(const char* why) {
|
||||
maybePause();
|
||||
@@ -195,12 +202,7 @@ class MIRGenerator
|
||||
|
||||
bool instrumentedProfiling_;
|
||||
bool instrumentedProfilingIsCached_;
|
||||
|
||||
// List of nursery objects used by this compilation. Can be traced by a
|
||||
// minor GC while compilation happens off-thread. This Vector should only
|
||||
// be accessed on the main thread (IonBuilder, nursery GC or
|
||||
// CodeGenerator::link).
|
||||
ObjectVector nurseryObjects_;
|
||||
bool safeForMinorGC_;
|
||||
|
||||
void addAbortedPreliminaryGroup(ObjectGroup* group);
|
||||
|
||||
@@ -230,12 +232,6 @@ class MIRGenerator
|
||||
public:
|
||||
const JitCompileOptions options;
|
||||
|
||||
void traceNurseryObjects(JSTracer* trc);
|
||||
|
||||
const ObjectVector& nurseryObjects() const {
|
||||
return nurseryObjects_;
|
||||
}
|
||||
|
||||
Label* conversionErrorLabel() const {
|
||||
MOZ_ASSERT((conversionErrorLabel_ != nullptr) == compilingAsmJS());
|
||||
return conversionErrorLabel_;
|
||||
|
||||
@@ -42,7 +42,7 @@ MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOpti
|
||||
modifiesFrameArguments_(false),
|
||||
instrumentedProfiling_(false),
|
||||
instrumentedProfilingIsCached_(false),
|
||||
nurseryObjects_(*alloc),
|
||||
safeForMinorGC_(true),
|
||||
outOfBoundsLabel_(outOfBoundsLabel),
|
||||
conversionErrorLabel_(conversionErrorLabel),
|
||||
#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace jit {
|
||||
|
||||
#define MIR_OPCODE_LIST(_) \
|
||||
_(Constant) \
|
||||
_(NurseryObject) \
|
||||
_(SimdBox) \
|
||||
_(SimdUnbox) \
|
||||
_(SimdValueX4) \
|
||||
|
||||
@@ -29,45 +29,8 @@ using namespace js::jit;
|
||||
using JS::GenericNaN;
|
||||
using JS::ToInt32;
|
||||
|
||||
namespace {
|
||||
|
||||
// Emulate a TypeSet logic from a Type object to avoid duplicating the guard
|
||||
// logic.
|
||||
class TypeWrapper {
|
||||
TypeSet::Type t_;
|
||||
|
||||
public:
|
||||
explicit TypeWrapper(TypeSet::Type t) : t_(t) {}
|
||||
|
||||
inline bool unknown() const {
|
||||
return t_.isUnknown();
|
||||
}
|
||||
inline bool hasType(TypeSet::Type t) const {
|
||||
if (t == TypeSet::Int32Type())
|
||||
return t == t_ || t_ == TypeSet::DoubleType();
|
||||
return t == t_;
|
||||
}
|
||||
inline unsigned getObjectCount() const {
|
||||
if (t_.isAnyObject() || t_.isUnknown() || !t_.isObject())
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
inline JSObject* getSingletonNoBarrier(unsigned) const {
|
||||
if (t_.isSingleton())
|
||||
return t_.singletonNoBarrier();
|
||||
return nullptr;
|
||||
}
|
||||
inline ObjectGroup* getGroupNoBarrier(unsigned) const {
|
||||
if (t_.isGroup())
|
||||
return t_.groupNoBarrier();
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
template <typename Source, typename Set> void
|
||||
MacroAssembler::guardTypeSet(const Source& address, const Set* types, BarrierKind kind,
|
||||
template <typename Source> void
|
||||
MacroAssembler::guardTypeSet(const Source& address, const TypeSet *types, BarrierKind kind,
|
||||
Register scratch, Label* miss)
|
||||
{
|
||||
MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
|
||||
@@ -139,7 +102,7 @@ MacroAssembler::guardTypeSet(const Source& address, const Set* types, BarrierKin
|
||||
|
||||
if (obj == scratch)
|
||||
extractObject(address, scratch);
|
||||
guardTypeSetMightBeIncomplete(obj, scratch, &matched);
|
||||
guardTypeSetMightBeIncomplete(types, obj, scratch, &matched);
|
||||
|
||||
assumeUnreachable("Unexpected object type");
|
||||
#endif
|
||||
@@ -148,29 +111,46 @@ MacroAssembler::guardTypeSet(const Source& address, const Set* types, BarrierKin
|
||||
bind(&matched);
|
||||
}
|
||||
|
||||
template <typename TypeSet>
|
||||
void
|
||||
MacroAssembler::guardTypeSetMightBeIncomplete(Register obj, Register scratch, Label* label)
|
||||
MacroAssembler::guardTypeSetMightBeIncomplete(TypeSet* types, Register obj, Register scratch, Label* label)
|
||||
{
|
||||
// Type set guards might miss when an object's group changes. In this case
|
||||
// either its properties will become unknown, or it will change to a native
|
||||
// object with an original unboxed group. Jump to label if this might have
|
||||
// happened for the input object.
|
||||
// either its old group's properties will become unknown, or it will change
|
||||
// to a native object with an original unboxed group. Jump to label if this
|
||||
// might have happened for the input object.
|
||||
|
||||
if (types->unknownObject()) {
|
||||
jump(label);
|
||||
return;
|
||||
}
|
||||
|
||||
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
|
||||
load32(Address(scratch, ObjectGroup::offsetOfFlags()), scratch);
|
||||
branchTest32(Assembler::NonZero, scratch, Imm32(OBJECT_FLAG_UNKNOWN_PROPERTIES), label);
|
||||
and32(Imm32(OBJECT_FLAG_ADDENDUM_MASK), scratch);
|
||||
branch32(Assembler::Equal,
|
||||
scratch, Imm32(ObjectGroup::addendumOriginalUnboxedGroupValue()), label);
|
||||
|
||||
for (size_t i = 0; i < types->getObjectCount(); i++) {
|
||||
if (JSObject* singleton = types->getSingletonNoBarrier(i)) {
|
||||
movePtr(ImmGCPtr(singleton), scratch);
|
||||
loadPtr(Address(scratch, JSObject::offsetOfGroup()), scratch);
|
||||
} else if (ObjectGroup* group = types->getGroupNoBarrier(i)) {
|
||||
movePtr(ImmGCPtr(group), scratch);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
branchTest32(Assembler::NonZero, Address(scratch, ObjectGroup::offsetOfFlags()),
|
||||
Imm32(OBJECT_FLAG_UNKNOWN_PROPERTIES), label);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Set> void
|
||||
MacroAssembler::guardObjectType(Register obj, const Set* types,
|
||||
void
|
||||
MacroAssembler::guardObjectType(Register obj, const TypeSet* types,
|
||||
Register scratch, Label* miss)
|
||||
{
|
||||
MOZ_ASSERT(!types->unknown());
|
||||
MOZ_ASSERT(!types->hasType(TypeSet::AnyObjectType()));
|
||||
MOZ_ASSERT(types->getObjectCount());
|
||||
MOZ_ASSERT(scratch != InvalidReg);
|
||||
|
||||
// Note: this method elides read barriers on values read from type sets, as
|
||||
@@ -236,47 +216,16 @@ MacroAssembler::guardObjectType(Register obj, const Set* types,
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename Source> void
|
||||
MacroAssembler::guardType(const Source& address, TypeSet::Type type,
|
||||
Register scratch, Label* miss)
|
||||
{
|
||||
TypeWrapper wrapper(type);
|
||||
guardTypeSet(address, &wrapper, BarrierKind::TypeSet, scratch, miss);
|
||||
}
|
||||
|
||||
template void MacroAssembler::guardTypeSet(const Address& address, const TemporaryTypeSet* types,
|
||||
BarrierKind kind, Register scratch, Label* miss);
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand& value, const TemporaryTypeSet* types,
|
||||
BarrierKind kind, Register scratch, Label* miss);
|
||||
|
||||
template void MacroAssembler::guardTypeSet(const Address& address, const HeapTypeSet* types,
|
||||
BarrierKind kind, Register scratch, Label* miss);
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand& value, const HeapTypeSet* types,
|
||||
BarrierKind kind, Register scratch, Label* miss);
|
||||
template void MacroAssembler::guardTypeSet(const TypedOrValueRegister& reg, const HeapTypeSet* types,
|
||||
BarrierKind kind, Register scratch, Label* miss);
|
||||
|
||||
template void MacroAssembler::guardTypeSet(const Address& address, const TypeSet* types,
|
||||
BarrierKind kind, Register scratch, Label* miss);
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand& value, const TypeSet* types,
|
||||
BarrierKind kind, Register scratch, Label* miss);
|
||||
|
||||
template void MacroAssembler::guardTypeSet(const Address& address, const TypeWrapper* types,
|
||||
BarrierKind kind, Register scratch, Label* miss);
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand& value, const TypeWrapper* types,
|
||||
template void MacroAssembler::guardTypeSet(const TypedOrValueRegister& value, const TypeSet* types,
|
||||
BarrierKind kind, Register scratch, Label* miss);
|
||||
|
||||
template void MacroAssembler::guardObjectType(Register obj, const TemporaryTypeSet* types,
|
||||
Register scratch, Label* miss);
|
||||
template void MacroAssembler::guardObjectType(Register obj, const TypeSet* types,
|
||||
Register scratch, Label* miss);
|
||||
template void MacroAssembler::guardObjectType(Register obj, const TypeWrapper* types,
|
||||
Register scratch, Label* miss);
|
||||
|
||||
template void MacroAssembler::guardType(const Address& address, TypeSet::Type type,
|
||||
Register scratch, Label* miss);
|
||||
template void MacroAssembler::guardType(const ValueOperand& value, TypeSet::Type type,
|
||||
Register scratch, Label* miss);
|
||||
template void MacroAssembler::guardTypeSetMightBeIncomplete(const TemporaryTypeSet* types,
|
||||
Register obj, Register scratch,
|
||||
Label* label);
|
||||
|
||||
template<typename S, typename T>
|
||||
static void
|
||||
@@ -798,8 +747,16 @@ void
|
||||
MacroAssembler::loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output)
|
||||
{
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_INT32: {
|
||||
// Handle loading an int32 into a double reg.
|
||||
if (output.type() == MIRType_Double) {
|
||||
convertInt32ToDouble(address, output.typedReg().fpu());
|
||||
break;
|
||||
}
|
||||
// Fallthrough.
|
||||
}
|
||||
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
case JSVAL_TYPE_INT32:
|
||||
case JSVAL_TYPE_STRING: {
|
||||
Register outReg;
|
||||
if (output.hasValue()) {
|
||||
|
||||
@@ -350,14 +350,13 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
|
||||
// Emits a test of a value against all types in a TypeSet. A scratch
|
||||
// register is required.
|
||||
template <typename Source, typename TypeSet>
|
||||
void guardTypeSet(const Source& address, const TypeSet* types, BarrierKind kind, Register scratch, Label* miss);
|
||||
template <typename TypeSet>
|
||||
void guardObjectType(Register obj, const TypeSet* types, Register scratch, Label* miss);
|
||||
template <typename Source>
|
||||
void guardType(const Source& address, TypeSet::Type type, Register scratch, Label* miss);
|
||||
void guardTypeSet(const Source& address, const TypeSet* types, BarrierKind kind, Register scratch, Label* miss);
|
||||
|
||||
void guardTypeSetMightBeIncomplete(Register obj, Register scratch, Label* label);
|
||||
void guardObjectType(Register obj, const TypeSet* types, Register scratch, Label* miss);
|
||||
|
||||
template <typename TypeSet>
|
||||
void guardTypeSetMightBeIncomplete(TypeSet* types, Register obj, Register scratch, Label* label);
|
||||
|
||||
void loadObjShape(Register objReg, Register dest) {
|
||||
loadPtr(Address(objReg, JSObject::offsetOfShape()), dest);
|
||||
@@ -942,6 +941,15 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
branchTestClassIsProxy(proxy, scratch, label);
|
||||
}
|
||||
|
||||
void branchFunctionKind(Condition cond, JSFunction::FunctionKind kind, Register fun,
|
||||
Register scratch, Label* label)
|
||||
{
|
||||
Address flags(fun, JSFunction::offsetOfFlags());
|
||||
load32(flags, scratch);
|
||||
and32(Imm32(JSFunction::FUNCTION_KIND_MASK), scratch);
|
||||
branch32(cond, scratch, Imm32(kind << JSFunction::FUNCTION_KIND_SHIFT), label);
|
||||
}
|
||||
|
||||
public:
|
||||
#ifndef JS_CODEGEN_ARM64
|
||||
// StackPointer manipulation functions.
|
||||
|
||||
@@ -91,7 +91,7 @@ CheckOverRecursed(JSContext* cx)
|
||||
// - jitStackLimit was the real stack limit and we're over-recursed
|
||||
// - jitStackLimit was set to UINTPTR_MAX by JSRuntime::requestInterrupt
|
||||
// and we need to call JSRuntime::handleInterrupt.
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, 0, return false);
|
||||
#else
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
@@ -121,7 +121,7 @@ CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
|
||||
uint8_t spDummy;
|
||||
uint8_t* checkSp = (&spDummy) - extra;
|
||||
if (earlyCheck) {
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
(void)checkSp;
|
||||
JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, frame->setOverRecursed());
|
||||
#else
|
||||
@@ -135,7 +135,7 @@ CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
|
||||
if (frame->overRecursed())
|
||||
return false;
|
||||
|
||||
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR
|
||||
JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, return false);
|
||||
#else
|
||||
JS_CHECK_RECURSION_WITH_SP(cx, checkSp, return false);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "jit/arm/Architecture-arm.h"
|
||||
|
||||
#ifndef JS_ARM_SIMULATOR
|
||||
#ifndef JS_SIMULATOR_ARM
|
||||
#include <elf.h>
|
||||
#endif
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "jit/arm/Assembler-arm.h"
|
||||
#include "jit/RegisterSets.h"
|
||||
|
||||
#if !defined(__linux__) || defined(ANDROID) || defined(JS_ARM_SIMULATOR)
|
||||
#if !defined(__linux__) || defined(ANDROID) || defined(JS_SIMULATOR_ARM)
|
||||
// The Android NDK and B2G do not include the hwcap.h kernel header, and it is not
|
||||
// defined when building the simulator, so inline the header defines we need.
|
||||
# define HWCAP_VFP (1 << 6)
|
||||
@@ -88,7 +88,7 @@ ParseARMCpuFeatures(const char* features, bool override = false)
|
||||
flags |= HWCAP_ARMv7;
|
||||
else if (count == 5 && strncmp(features, "align", 5) == 0)
|
||||
flags |= HWCAP_ALIGNMENT_FAULT;
|
||||
#if defined(JS_ARM_SIMULATOR)
|
||||
#if defined(JS_SIMULATOR_ARM)
|
||||
else if (count == 6 && strncmp(features, "hardfp", 6) == 0)
|
||||
flags |= HWCAP_USE_HARDFP_ABI;
|
||||
#endif
|
||||
@@ -154,7 +154,7 @@ ParseARMHwCapFlags(const char* armHwCap)
|
||||
" vfpd32 \n"
|
||||
" armv7 \n"
|
||||
" align \n"
|
||||
#if defined(JS_ARM_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR_ARM
|
||||
" hardfp \n"
|
||||
#endif
|
||||
"\n"
|
||||
@@ -186,7 +186,7 @@ InitARMFlags()
|
||||
if (ParseARMHwCapFlags(env))
|
||||
return;
|
||||
|
||||
#ifdef JS_ARM_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM
|
||||
flags = HWCAP_ARMv7 | HWCAP_VFP | HWCAP_VFPv3 | HWCAP_VFPv4 | HWCAP_NEON;
|
||||
#else
|
||||
|
||||
@@ -245,7 +245,7 @@ InitARMFlags()
|
||||
flags |= HWCAP_ARMv7;
|
||||
#endif
|
||||
|
||||
#endif // JS_ARM_SIMULATOR
|
||||
#endif // JS_SIMULATOR_ARM
|
||||
|
||||
armHwCapFlags = CanonicalizeARMHwCapFlags(flags);
|
||||
|
||||
@@ -304,7 +304,7 @@ bool HasIDIV()
|
||||
}
|
||||
|
||||
// This is defined in the header and inlined when not using the simulator.
|
||||
#if defined(JS_ARM_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR_ARM
|
||||
bool UseHardFpABI()
|
||||
{
|
||||
MOZ_ASSERT(armHwCapFlags != HWCAP_UNINITIALIZED);
|
||||
|
||||
@@ -626,7 +626,7 @@ uint32_t GetARMFlags();
|
||||
// If the simulator is used then the ABI choice is dynamic. Otherwise the ABI is
|
||||
// static and useHardFpABI is inlined so that unused branches can be optimized
|
||||
// away.
|
||||
#if defined(JS_ARM_SIMULATOR)
|
||||
#ifdef JS_SIMULATOR_ARM
|
||||
bool UseHardFpABI();
|
||||
#else
|
||||
static inline bool UseHardFpABI()
|
||||
|
||||
+116
-157
@@ -26,12 +26,12 @@ void dbg_break() {}
|
||||
|
||||
// Note this is used for inter-AsmJS calls and may pass arguments and results in
|
||||
// floating point registers even if the system ABI does not.
|
||||
ABIArgGenerator::ABIArgGenerator() :
|
||||
intRegIndex_(0),
|
||||
ABIArgGenerator::ABIArgGenerator()
|
||||
: intRegIndex_(0),
|
||||
floatRegIndex_(0),
|
||||
stackOffset_(0),
|
||||
current_()
|
||||
{}
|
||||
{ }
|
||||
|
||||
ABIArg
|
||||
ABIArgGenerator::next(MIRType type)
|
||||
@@ -498,15 +498,17 @@ InstMOV::IsTHIS(const Instruction& i)
|
||||
}
|
||||
|
||||
Op2Reg
|
||||
Operand2::toOp2Reg() {
|
||||
Operand2::toOp2Reg() const {
|
||||
return *(Op2Reg*)this;
|
||||
}
|
||||
|
||||
O2RegImmShift
|
||||
Op2Reg::toO2RegImmShift() {
|
||||
Op2Reg::toO2RegImmShift() const {
|
||||
return *(O2RegImmShift*)this;
|
||||
}
|
||||
|
||||
O2RegRegShift
|
||||
Op2Reg::toO2RegRegShift() {
|
||||
Op2Reg::toO2RegRegShift() const {
|
||||
return *(O2RegRegShift*)this;
|
||||
}
|
||||
|
||||
@@ -529,7 +531,7 @@ Imm16::Imm16()
|
||||
{ }
|
||||
|
||||
void
|
||||
jit::PatchJump(CodeLocationJump& jump_, CodeLocationLabel label)
|
||||
jit::PatchJump(CodeLocationJump& jump_, CodeLocationLabel label, ReprotectCode reprotect)
|
||||
{
|
||||
// We need to determine if this jump can fit into the standard 24+2 bit
|
||||
// address or if we need a larger branch (or just need to use our pool
|
||||
@@ -543,11 +545,18 @@ jit::PatchJump(CodeLocationJump& jump_, CodeLocationLabel label)
|
||||
int jumpOffset = label.raw() - jump_.raw();
|
||||
if (BOffImm::IsInRange(jumpOffset)) {
|
||||
// This instruction started off as a branch, and will remain one.
|
||||
MaybeAutoWritableJitCode awjc(jump, sizeof(Instruction), reprotect);
|
||||
Assembler::RetargetNearBranch(jump, jumpOffset, c);
|
||||
} else {
|
||||
// This instruction started off as a branch, but now needs to be demoted
|
||||
// to an ldr.
|
||||
uint8_t** slot = reinterpret_cast<uint8_t**>(jump_.jumpTableEntry());
|
||||
|
||||
// Ensure both the branch and the slot are writable.
|
||||
MOZ_ASSERT(uintptr_t(slot) > uintptr_t(jump));
|
||||
size_t size = uintptr_t(slot) - uintptr_t(jump) + sizeof(void*);
|
||||
MaybeAutoWritableJitCode awjc(jump, size, reprotect);
|
||||
|
||||
Assembler::RetargetFarBranch(jump, slot, label.raw(), c);
|
||||
}
|
||||
}
|
||||
@@ -805,12 +814,6 @@ TraceOneDataRelocation(JSTracer* trc, Iter* iter)
|
||||
const void* prior = Assembler::GetPtr32Target(iter, &dest, &rs);
|
||||
void* ptr = const_cast<void*>(prior);
|
||||
|
||||
// The low bit shouldn't be set. If it is, we probably got a dummy
|
||||
// pointer inserted by CodeGenerator::visitNurseryObject, but we
|
||||
// shouldn't be able to trigger GC before those are patched to their
|
||||
// real values.
|
||||
MOZ_ASSERT(!(uintptr_t(ptr) & 0x1));
|
||||
|
||||
// No barrier needed since these are constants.
|
||||
TraceManuallyBarrieredGenericPointerEdge(trc, reinterpret_cast<gc::Cell**>(&ptr),
|
||||
"ion-masm-ptr");
|
||||
@@ -853,50 +856,6 @@ Assembler::TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReade
|
||||
::TraceDataRelocations(trc, code->raw(), reader);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::FixupNurseryObjects(JSContext* cx, JitCode* code, CompactBufferReader& reader,
|
||||
const ObjectVector& nurseryObjects)
|
||||
{
|
||||
MOZ_ASSERT(!nurseryObjects.empty());
|
||||
|
||||
uint8_t* buffer = code->raw();
|
||||
bool hasNurseryPointers = false;
|
||||
|
||||
while (reader.more()) {
|
||||
size_t offset = reader.readUnsigned();
|
||||
InstructionIterator iter((Instruction*)(buffer + offset));
|
||||
Instruction* ins = iter.cur();
|
||||
Register dest;
|
||||
Assembler::RelocStyle rs;
|
||||
const void* prior = Assembler::GetPtr32Target(&iter, &dest, &rs);
|
||||
void* ptr = const_cast<void*>(prior);
|
||||
uintptr_t word = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
if (!(word & 0x1))
|
||||
continue;
|
||||
|
||||
uint32_t index = word >> 1;
|
||||
JSObject* obj = nurseryObjects[index];
|
||||
MacroAssembler::ma_mov_patch(Imm32(int32_t(obj)), dest, Assembler::Always, rs, ins);
|
||||
|
||||
if (rs != Assembler::L_LDR) {
|
||||
// L_LDR won't cause any instructions to be updated.
|
||||
AutoFlushICache::flush(uintptr_t(ins), 4);
|
||||
AutoFlushICache::flush(uintptr_t(ins->next()), 4);
|
||||
}
|
||||
|
||||
// Either all objects are still in the nursery, or all objects are
|
||||
// tenured.
|
||||
MOZ_ASSERT_IF(hasNurseryPointers, IsInsideNursery(obj));
|
||||
|
||||
if (!hasNurseryPointers && IsInsideNursery(obj))
|
||||
hasNurseryPointers = true;
|
||||
}
|
||||
|
||||
if (hasNurseryPointers)
|
||||
cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(code);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::copyJumpRelocationTable(uint8_t* dest)
|
||||
{
|
||||
@@ -1257,7 +1216,7 @@ BOffImm::BOffImm(Instruction& inst)
|
||||
}
|
||||
|
||||
Instruction*
|
||||
BOffImm::getDest(Instruction* src)
|
||||
BOffImm::getDest(Instruction* src) const
|
||||
{
|
||||
// TODO: It is probably worthwhile to verify that src is actually a branch.
|
||||
// NOTE: This does not explicitly shift the offset of the destination left by 2,
|
||||
@@ -1425,120 +1384,119 @@ Assembler::as_nop()
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
EncodeAlu(Register dest, Register src1, Operand2 op2, ALUOp op, SetCond_ sc,
|
||||
Assembler::Condition c)
|
||||
EncodeAlu(Register dest, Register src1, Operand2 op2, ALUOp op, SBit s, Assembler::Condition c)
|
||||
{
|
||||
return (int)op | (int)sc | (int) c | op2.encode() |
|
||||
return (int)op | (int)s | (int)c | op2.encode() |
|
||||
((dest == InvalidReg) ? 0 : RD(dest)) |
|
||||
((src1 == InvalidReg) ? 0 : RN(src1));
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_alu(Register dest, Register src1, Operand2 op2,
|
||||
ALUOp op, SetCond_ sc, Condition c)
|
||||
ALUOp op, SBit s, Condition c)
|
||||
{
|
||||
return writeInst(EncodeAlu(dest, src1, op2, op, sc, c));
|
||||
return writeInst(EncodeAlu(dest, src1, op2, op, s, c));
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_mov(Register dest, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_mov(Register dest, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, InvalidReg, op2, OpMov, sc, c);
|
||||
return as_alu(dest, InvalidReg, op2, OpMov, s, c);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
Assembler::as_alu_patch(Register dest, Register src1, Operand2 op2, ALUOp op, SetCond_ sc,
|
||||
Assembler::as_alu_patch(Register dest, Register src1, Operand2 op2, ALUOp op, SBit s,
|
||||
Condition c, uint32_t* pos)
|
||||
{
|
||||
WriteInstStatic(EncodeAlu(dest, src1, op2, op, sc, c), pos);
|
||||
WriteInstStatic(EncodeAlu(dest, src1, op2, op, s, c), pos);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
Assembler::as_mov_patch(Register dest, Operand2 op2, SetCond_ sc, Condition c, uint32_t* pos)
|
||||
Assembler::as_mov_patch(Register dest, Operand2 op2, SBit s, Condition c, uint32_t* pos)
|
||||
{
|
||||
as_alu_patch(dest, InvalidReg, op2, OpMov, sc, c, pos);
|
||||
as_alu_patch(dest, InvalidReg, op2, OpMov, s, c, pos);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_mvn(Register dest, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_mvn(Register dest, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, InvalidReg, op2, OpMvn, sc, c);
|
||||
return as_alu(dest, InvalidReg, op2, OpMvn, s, c);
|
||||
}
|
||||
|
||||
// Logical operations.
|
||||
BufferOffset
|
||||
Assembler::as_and(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_and(Register dest, Register src1, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, src1, op2, OpAnd, sc, c);
|
||||
return as_alu(dest, src1, op2, OpAnd, s, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_bic(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_bic(Register dest, Register src1, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, src1, op2, OpBic, sc, c);
|
||||
return as_alu(dest, src1, op2, OpBic, s, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_eor(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_eor(Register dest, Register src1, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, src1, op2, OpEor, sc, c);
|
||||
return as_alu(dest, src1, op2, OpEor, s, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_orr(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_orr(Register dest, Register src1, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, src1, op2, OpOrr, sc, c);
|
||||
return as_alu(dest, src1, op2, OpOrr, s, c);
|
||||
}
|
||||
|
||||
// Mathematical operations.
|
||||
BufferOffset
|
||||
Assembler::as_adc(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_adc(Register dest, Register src1, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, src1, op2, OpAdc, sc, c);
|
||||
return as_alu(dest, src1, op2, OpAdc, s, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_add(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_add(Register dest, Register src1, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, src1, op2, OpAdd, sc, c);
|
||||
return as_alu(dest, src1, op2, OpAdd, s, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_sbc(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_sbc(Register dest, Register src1, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, src1, op2, OpSbc, sc, c);
|
||||
return as_alu(dest, src1, op2, OpSbc, s, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_sub(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_sub(Register dest, Register src1, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, src1, op2, OpSub, sc, c);
|
||||
return as_alu(dest, src1, op2, OpSub, s, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_rsb(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_rsb(Register dest, Register src1, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, src1, op2, OpRsb, sc, c);
|
||||
return as_alu(dest, src1, op2, OpRsb, s, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_rsc(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
|
||||
Assembler::as_rsc(Register dest, Register src1, Operand2 op2, SBit s, Condition c)
|
||||
{
|
||||
return as_alu(dest, src1, op2, OpRsc, sc, c);
|
||||
return as_alu(dest, src1, op2, OpRsc, s, c);
|
||||
}
|
||||
|
||||
// Test operations.
|
||||
BufferOffset
|
||||
Assembler::as_cmn(Register src1, Operand2 op2, Condition c)
|
||||
{
|
||||
return as_alu(InvalidReg, src1, op2, OpCmn, SetCond, c);
|
||||
return as_alu(InvalidReg, src1, op2, OpCmn, SetCC, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_cmp(Register src1, Operand2 op2, Condition c)
|
||||
{
|
||||
return as_alu(InvalidReg, src1, op2, OpCmp, SetCond, c);
|
||||
return as_alu(InvalidReg, src1, op2, OpCmp, SetCC, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_teq(Register src1, Operand2 op2, Condition c)
|
||||
{
|
||||
return as_alu(InvalidReg, src1, op2, OpTeq, SetCond, c);
|
||||
return as_alu(InvalidReg, src1, op2, OpTeq, SetCC, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_tst(Register src1, Operand2 op2, Condition c)
|
||||
{
|
||||
return as_alu(InvalidReg, src1, op2, OpTst, SetCond, c);
|
||||
return as_alu(InvalidReg, src1, op2, OpTst, SetCC, c);
|
||||
}
|
||||
|
||||
static MOZ_CONSTEXPR_VAR Register NoAddend = { Registers::pc };
|
||||
@@ -1619,59 +1577,59 @@ static const int mull_tag = 0x90;
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_genmul(Register dhi, Register dlo, Register rm, Register rn,
|
||||
MULOp op, SetCond_ sc, Condition c)
|
||||
MULOp op, SBit s, Condition c)
|
||||
{
|
||||
|
||||
return writeInst(RN(dhi) | maybeRD(dlo) | RM(rm) | rn.code() | op | sc | c | mull_tag);
|
||||
return writeInst(RN(dhi) | maybeRD(dlo) | RM(rm) | rn.code() | op | s | c | mull_tag);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_mul(Register dest, Register src1, Register src2, SetCond_ sc, Condition c)
|
||||
Assembler::as_mul(Register dest, Register src1, Register src2, SBit s, Condition c)
|
||||
{
|
||||
return as_genmul(dest, InvalidReg, src1, src2, OpmMul, sc, c);
|
||||
return as_genmul(dest, InvalidReg, src1, src2, OpmMul, s, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_mla(Register dest, Register acc, Register src1, Register src2,
|
||||
SetCond_ sc, Condition c)
|
||||
SBit s, Condition c)
|
||||
{
|
||||
return as_genmul(dest, acc, src1, src2, OpmMla, sc, c);
|
||||
return as_genmul(dest, acc, src1, src2, OpmMla, s, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_umaal(Register destHI, Register destLO, Register src1, Register src2, Condition c)
|
||||
{
|
||||
return as_genmul(destHI, destLO, src1, src2, OpmUmaal, NoSetCond, c);
|
||||
return as_genmul(destHI, destLO, src1, src2, OpmUmaal, LeaveCC, c);
|
||||
}
|
||||
BufferOffset
|
||||
Assembler::as_mls(Register dest, Register acc, Register src1, Register src2, Condition c)
|
||||
{
|
||||
return as_genmul(dest, acc, src1, src2, OpmMls, NoSetCond, c);
|
||||
return as_genmul(dest, acc, src1, src2, OpmMls, LeaveCC, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_umull(Register destHI, Register destLO, Register src1, Register src2,
|
||||
SetCond_ sc, Condition c)
|
||||
SBit s, Condition c)
|
||||
{
|
||||
return as_genmul(destHI, destLO, src1, src2, OpmUmull, sc, c);
|
||||
return as_genmul(destHI, destLO, src1, src2, OpmUmull, s, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_umlal(Register destHI, Register destLO, Register src1, Register src2,
|
||||
SetCond_ sc, Condition c)
|
||||
SBit s, Condition c)
|
||||
{
|
||||
return as_genmul(destHI, destLO, src1, src2, OpmUmlal, sc, c);
|
||||
return as_genmul(destHI, destLO, src1, src2, OpmUmlal, s, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_smull(Register destHI, Register destLO, Register src1, Register src2,
|
||||
SetCond_ sc, Condition c)
|
||||
SBit s, Condition c)
|
||||
{
|
||||
return as_genmul(destHI, destLO, src1, src2, OpmSmull, sc, c);
|
||||
return as_genmul(destHI, destLO, src1, src2, OpmSmull, s, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_smlal(Register destHI, Register destLO, Register src1, Register src2,
|
||||
SetCond_ sc, Condition c)
|
||||
SBit s, Condition c)
|
||||
{
|
||||
return as_genmul(destHI, destLO, src1, src2, OpmSmlal, sc, c);
|
||||
return as_genmul(destHI, destLO, src1, src2, OpmSmlal, s, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
@@ -1716,7 +1674,8 @@ Assembler::as_dtr_patch(LoadStore ls, int size, Index mode, Register rt, DTRAddr
|
||||
WriteInstStatic(EncodeDtr(ls, size, mode, rt, addr, c), dest);
|
||||
}
|
||||
|
||||
class PoolHintData {
|
||||
class PoolHintData
|
||||
{
|
||||
public:
|
||||
enum LoadType {
|
||||
// Set 0 to bogus, since that is the value most likely to be
|
||||
@@ -1759,19 +1718,19 @@ class PoolHintData {
|
||||
destReg_ = destReg.id();
|
||||
destType_ = destReg.isDouble();
|
||||
}
|
||||
Assembler::Condition getCond() {
|
||||
Assembler::Condition getCond() const {
|
||||
return Assembler::Condition(cond_ << 28);
|
||||
}
|
||||
|
||||
Register getReg() {
|
||||
Register getReg() const {
|
||||
return Register::FromCode(destReg_);
|
||||
}
|
||||
VFPRegister getVFPReg() {
|
||||
VFPRegister getVFPReg() const {
|
||||
VFPRegister r = VFPRegister(destReg_, destType_ ? VFPRegister::Double : VFPRegister::Single);
|
||||
return r;
|
||||
}
|
||||
|
||||
int32_t getIndex() {
|
||||
int32_t getIndex() const {
|
||||
return index_;
|
||||
}
|
||||
void setIndex(uint32_t index) {
|
||||
@@ -1780,7 +1739,7 @@ class PoolHintData {
|
||||
MOZ_ASSERT(index_ == index);
|
||||
}
|
||||
|
||||
LoadType getLoadType() {
|
||||
LoadType getLoadType() const {
|
||||
// If this *was* a PoolBranch, but the branch has already been bound
|
||||
// then this isn't going to look like a real poolhintdata, but we still
|
||||
// want to lie about it so everyone knows it *used* to be a branch.
|
||||
@@ -1789,7 +1748,7 @@ class PoolHintData {
|
||||
return loadType_;
|
||||
}
|
||||
|
||||
bool isValidPoolHint() {
|
||||
bool isValidPoolHint() const {
|
||||
// Most instructions cannot have a condition that is 0xf. Notable
|
||||
// exceptions are blx and the entire NEON instruction set. For the
|
||||
// purposes of pool loads, and possibly patched branches, the possible
|
||||
@@ -1799,7 +1758,8 @@ class PoolHintData {
|
||||
}
|
||||
};
|
||||
|
||||
union PoolHintPun {
|
||||
union PoolHintPun
|
||||
{
|
||||
PoolHintData phd;
|
||||
uint32_t raw;
|
||||
};
|
||||
@@ -1844,8 +1804,7 @@ BufferOffset
|
||||
Assembler::as_dtm(LoadStore ls, Register rn, uint32_t mask,
|
||||
DTMMode mode, DTMWriteBack wb, Condition c)
|
||||
{
|
||||
return writeInst(0x08000000 | RN(rn) | ls |
|
||||
mode | mask | c | wb);
|
||||
return writeInst(0x08000000 | RN(rn) | ls | mode | mask | c | wb);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
@@ -2056,12 +2015,14 @@ Assembler::as_bx(Register r, Condition c)
|
||||
BufferOffset ret = writeInst(((int) c) | OpBx | r.code());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::WritePoolGuard(BufferOffset branch, Instruction* dest, BufferOffset afterPool)
|
||||
{
|
||||
BOffImm off = afterPool.diffB<BOffImm>(branch);
|
||||
*dest = InstBImm(off, Always);
|
||||
}
|
||||
|
||||
// Branch can branch to an immediate *or* to a register.
|
||||
// Branches to immediates are pc relative, branches to registers are absolute.
|
||||
BufferOffset
|
||||
@@ -2106,6 +2067,7 @@ Assembler::as_b(Label* l, Condition c)
|
||||
MOZ_ASSERT(check == old);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_b(BOffImm off, Condition c, BufferOffset inst)
|
||||
{
|
||||
@@ -2168,6 +2130,7 @@ Assembler::as_bl(Label* l, Condition c)
|
||||
MOZ_ASSERT(check == old);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_bl(BOffImm off, Condition c, BufferOffset inst)
|
||||
{
|
||||
@@ -2195,6 +2158,7 @@ enum vfp_tags {
|
||||
VfpTag = 0x0C000A00,
|
||||
VfpArith = 0x02000000
|
||||
};
|
||||
|
||||
BufferOffset
|
||||
Assembler::writeVFPInst(vfp_size sz, uint32_t blob)
|
||||
{
|
||||
@@ -2225,43 +2189,37 @@ Assembler::as_vfp_float(VFPRegister vd, VFPRegister vn, VFPRegister vm,
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_vadd(VFPRegister vd, VFPRegister vn, VFPRegister vm,
|
||||
Condition c)
|
||||
Assembler::as_vadd(VFPRegister vd, VFPRegister vn, VFPRegister vm, Condition c)
|
||||
{
|
||||
return as_vfp_float(vd, vn, vm, OpvAdd, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_vdiv(VFPRegister vd, VFPRegister vn, VFPRegister vm,
|
||||
Condition c)
|
||||
Assembler::as_vdiv(VFPRegister vd, VFPRegister vn, VFPRegister vm, Condition c)
|
||||
{
|
||||
return as_vfp_float(vd, vn, vm, OpvDiv, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_vmul(VFPRegister vd, VFPRegister vn, VFPRegister vm,
|
||||
Condition c)
|
||||
Assembler::as_vmul(VFPRegister vd, VFPRegister vn, VFPRegister vm, Condition c)
|
||||
{
|
||||
return as_vfp_float(vd, vn, vm, OpvMul, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_vnmul(VFPRegister vd, VFPRegister vn, VFPRegister vm,
|
||||
Condition c)
|
||||
Assembler::as_vnmul(VFPRegister vd, VFPRegister vn, VFPRegister vm, Condition c)
|
||||
{
|
||||
return as_vfp_float(vd, vn, vm, OpvMul, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_vnmla(VFPRegister vd, VFPRegister vn, VFPRegister vm,
|
||||
Condition c)
|
||||
Assembler::as_vnmla(VFPRegister vd, VFPRegister vn, VFPRegister vm, Condition c)
|
||||
{
|
||||
MOZ_CRASH("Feature NYI");
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_vnmls(VFPRegister vd, VFPRegister vn, VFPRegister vm,
|
||||
Condition c)
|
||||
Assembler::as_vnmls(VFPRegister vd, VFPRegister vn, VFPRegister vm, Condition c)
|
||||
{
|
||||
MOZ_CRASH("Feature NYI");
|
||||
}
|
||||
@@ -2285,18 +2243,17 @@ Assembler::as_vabs(VFPRegister vd, VFPRegister vm, Condition c)
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_vsub(VFPRegister vd, VFPRegister vn, VFPRegister vm,
|
||||
Condition c)
|
||||
Assembler::as_vsub(VFPRegister vd, VFPRegister vn, VFPRegister vm, Condition c)
|
||||
{
|
||||
return as_vfp_float(vd, vn, vm, OpvSub, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_vcmp(VFPRegister vd, VFPRegister vm,
|
||||
Condition c)
|
||||
Assembler::as_vcmp(VFPRegister vd, VFPRegister vm, Condition c)
|
||||
{
|
||||
return as_vfp_float(vd, NoVFPRegister, vm, OpvCmp, c);
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_vcmpz(VFPRegister vd, Condition c)
|
||||
{
|
||||
@@ -2309,6 +2266,7 @@ Assembler::as_vmov(VFPRegister vd, VFPRegister vsrc, Condition c)
|
||||
{
|
||||
return as_vfp_float(vd, NoVFPRegister, vsrc, OpvMov, c);
|
||||
}
|
||||
|
||||
// Transfer between Core and VFP.
|
||||
|
||||
// Unlike the next function, moving between the core registers and vfp registers
|
||||
@@ -2339,15 +2297,13 @@ Assembler::as_vxfer(Register vt1, Register vt2, VFPRegister vm, FloatToCore_ f2c
|
||||
MOZ_ASSERT(idx == 0);
|
||||
}
|
||||
|
||||
if (vt2 == InvalidReg) {
|
||||
return writeVFPInst(sz, WordTransfer | f2c | c |
|
||||
RT(vt1) | maybeRN(vt2) | VN(vm) | idx);
|
||||
} else {
|
||||
// We are doing a 64 bit transfer.
|
||||
return writeVFPInst(sz, DoubleTransfer | f2c | c |
|
||||
RT(vt1) | maybeRN(vt2) | VM(vm) | idx);
|
||||
}
|
||||
if (vt2 == InvalidReg)
|
||||
return writeVFPInst(sz, WordTransfer | f2c | c | RT(vt1) | maybeRN(vt2) | VN(vm) | idx);
|
||||
|
||||
// We are doing a 64 bit transfer.
|
||||
return writeVFPInst(sz, DoubleTransfer | f2c | c | RT(vt1) | maybeRN(vt2) | VM(vm) | idx);
|
||||
}
|
||||
|
||||
enum vcvt_destFloatness {
|
||||
VcvtToInteger = 1 << 18,
|
||||
VcvtToFloat = 0 << 18
|
||||
@@ -2384,9 +2340,9 @@ Assembler::as_vcvt(VFPRegister vd, VFPRegister vm, bool useFPSCR,
|
||||
vcvt_Signedness opSign;
|
||||
vcvt_toZero doToZero = VcvtToFPSCR;
|
||||
MOZ_ASSERT(vd.isFloat() || vm.isFloat());
|
||||
if (vd.isSingle() || vm.isSingle()) {
|
||||
if (vd.isSingle() || vm.isSingle())
|
||||
sz = IsSingle;
|
||||
}
|
||||
|
||||
if (vd.isFloat()) {
|
||||
destFloat = VcvtToFloat;
|
||||
opSign = (vm.isSInt()) ? VcvtFromSigned : VcvtFromUnsigned;
|
||||
@@ -2459,6 +2415,7 @@ Assembler::as_vimm(VFPRegister vd, VFPImm imm, Condition c)
|
||||
return writeVFPInst(sz, c | imm.encode() | VD(vd) | 0x02B00000);
|
||||
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
Assembler::as_vmrs(Register r, Condition c)
|
||||
{
|
||||
@@ -2585,7 +2542,6 @@ Assembler::retarget(Label* label, Label* target)
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int stopBKPT = -1;
|
||||
void
|
||||
Assembler::as_bkpt()
|
||||
@@ -2640,6 +2596,7 @@ Assembler::GetBranchOffset(const Instruction* i_)
|
||||
i->extractImm(&dest);
|
||||
return dest.decode();
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::RetargetNearBranch(Instruction* i, int offset, bool final)
|
||||
{
|
||||
@@ -2675,7 +2632,8 @@ Assembler::RetargetFarBranch(Instruction* i, uint8_t** slot, uint8_t* dest, Cond
|
||||
|
||||
}
|
||||
|
||||
struct PoolHeader : Instruction {
|
||||
struct PoolHeader : Instruction
|
||||
{
|
||||
struct Header
|
||||
{
|
||||
// The size should take into account the pool header.
|
||||
@@ -2716,6 +2674,7 @@ struct PoolHeader : Instruction {
|
||||
Header tmp(this);
|
||||
return tmp.isNatural;
|
||||
}
|
||||
|
||||
static bool IsTHIS(const Instruction& i) {
|
||||
return (*i.raw() & 0xffff0000) == 0xffff0000;
|
||||
}
|
||||
@@ -2726,11 +2685,10 @@ struct PoolHeader : Instruction {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
Assembler::WritePoolHeader(uint8_t* start, Pool* p, bool isNatural)
|
||||
{
|
||||
STATIC_ASSERT(sizeof(PoolHeader) == 4);
|
||||
static_assert(sizeof(PoolHeader) == 4, "PoolHandler must have the correct size.");
|
||||
uint8_t* pool = start + 4;
|
||||
// Go through the usual rigmarole to get the size of the pool.
|
||||
pool += p->getPoolSize();
|
||||
@@ -2742,7 +2700,6 @@ Assembler::WritePoolHeader(uint8_t* start, Pool* p, bool isNatural)
|
||||
*(PoolHeader*)start = header;
|
||||
}
|
||||
|
||||
|
||||
// The size of an arbitrary 32-bit call in the instruction stream. On ARM this
|
||||
// sequence is |pc = ldr pc - 4; imm32| given that we never reach the imm32.
|
||||
uint32_t
|
||||
@@ -2750,6 +2707,7 @@ Assembler::PatchWrite_NearCallSize()
|
||||
{
|
||||
return sizeof(uint32_t);
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::PatchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall)
|
||||
{
|
||||
@@ -2761,8 +2719,8 @@ Assembler::PatchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall
|
||||
new (inst) InstBLImm(BOffImm(dest - (uint8_t*)inst) , Always);
|
||||
// Ensure everyone sees the code that was just written into memory.
|
||||
AutoFlushICache::flush(uintptr_t(inst), 4);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
|
||||
PatchedImmPtr expectedValue)
|
||||
@@ -2803,7 +2761,6 @@ Assembler::PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm) {
|
||||
*(raw - 1) = imm.value;
|
||||
}
|
||||
|
||||
|
||||
uint8_t*
|
||||
Assembler::NextInstruction(uint8_t* inst_, uint32_t* count)
|
||||
{
|
||||
@@ -2828,7 +2785,8 @@ InstIsGuard(Instruction* inst, const PoolHeader** ph)
|
||||
}
|
||||
|
||||
static bool
|
||||
InstIsBNop(Instruction* inst) {
|
||||
InstIsBNop(Instruction* inst)
|
||||
{
|
||||
// In some special situations, it is necessary to insert a NOP into the
|
||||
// instruction stream that nobody knows about, since nobody should know
|
||||
// about it, make sure it gets skipped when Instruction::next() is called.
|
||||
@@ -3031,13 +2989,14 @@ void Assembler::UpdateBoundsCheck(uint32_t heapSize, Instruction* inst)
|
||||
Imm8 imm8 = Imm8(heapSize);
|
||||
MOZ_ASSERT(!imm8.invalid);
|
||||
|
||||
*inst = InstALU(InvalidReg, index, imm8, OpCmp, SetCond, Always);
|
||||
*inst = InstALU(InvalidReg, index, imm8, OpCmp, SetCC, Always);
|
||||
// NOTE: we don't update the Auto Flush Cache! this function is currently
|
||||
// only called from within AsmJSModule::patchHeapAccesses, which does that
|
||||
// for us. Don't call this!
|
||||
}
|
||||
|
||||
InstructionIterator::InstructionIterator(Instruction* i_) : i(i_)
|
||||
InstructionIterator::InstructionIterator(Instruction* i_)
|
||||
: i(i_)
|
||||
{
|
||||
// Work around pools with an artificial pool guard and around nop-fill.
|
||||
i = i->skipPool();
|
||||
|
||||
+272
-212
File diff suppressed because it is too large
Load Diff
@@ -29,8 +29,8 @@ ICCompare_Int32::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
// Compare payload regs of R0 and R1.
|
||||
Assembler::Condition cond = JSOpToCondition(op, /* signed = */true);
|
||||
masm.cmp32(R0.payloadReg(), R1.payloadReg());
|
||||
masm.ma_mov(Imm32(1), R0.payloadReg(), NoSetCond, cond);
|
||||
masm.ma_mov(Imm32(0), R0.payloadReg(), NoSetCond, Assembler::InvertCondition(cond));
|
||||
masm.ma_mov(Imm32(1), R0.payloadReg(), LeaveCC, cond);
|
||||
masm.ma_mov(Imm32(0), R0.payloadReg(), LeaveCC, Assembler::InvertCondition(cond));
|
||||
|
||||
// Result is implicitly boxed already.
|
||||
masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.payloadReg(), R0);
|
||||
@@ -57,7 +57,7 @@ ICCompare_Double::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
|
||||
masm.compareDouble(FloatReg0, FloatReg1);
|
||||
masm.ma_mov(Imm32(0), dest);
|
||||
masm.ma_mov(Imm32(1), dest, NoSetCond, cond);
|
||||
masm.ma_mov(Imm32(1), dest, LeaveCC, cond);
|
||||
|
||||
masm.tagValue(JSVAL_TYPE_BOOLEAN, dest, R0);
|
||||
EmitReturnFromIC(masm);
|
||||
@@ -93,7 +93,7 @@ ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
Label maybeNegZero, revertRegister;
|
||||
switch(op_) {
|
||||
case JSOP_ADD:
|
||||
masm.ma_add(R0.payloadReg(), R1.payloadReg(), scratchReg, SetCond);
|
||||
masm.ma_add(R0.payloadReg(), R1.payloadReg(), scratchReg, SetCC);
|
||||
|
||||
// Just jump to failure on overflow. R0 and R1 are preserved, so we can
|
||||
// just jump to the next stub.
|
||||
@@ -104,7 +104,7 @@ ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
masm.mov(scratchReg, R0.payloadReg());
|
||||
break;
|
||||
case JSOP_SUB:
|
||||
masm.ma_sub(R0.payloadReg(), R1.payloadReg(), scratchReg, SetCond);
|
||||
masm.ma_sub(R0.payloadReg(), R1.payloadReg(), scratchReg, SetCC);
|
||||
masm.j(Assembler::Overflow, &failure);
|
||||
masm.mov(scratchReg, R0.payloadReg());
|
||||
break;
|
||||
|
||||
@@ -137,7 +137,7 @@ CodeGeneratorARM::visitCompare(LCompare* comp)
|
||||
else
|
||||
masm.ma_cmp(ToRegister(left), ToOperand(right));
|
||||
masm.ma_mov(Imm32(0), ToRegister(def));
|
||||
masm.ma_mov(Imm32(1), ToRegister(def), NoSetCond, cond);
|
||||
masm.ma_mov(Imm32(1), ToRegister(def), LeaveCC, cond);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -382,9 +382,9 @@ CodeGeneratorARM::visitAddI(LAddI* ins)
|
||||
const LDefinition* dest = ins->getDef(0);
|
||||
|
||||
if (rhs->isConstant())
|
||||
masm.ma_add(ToRegister(lhs), Imm32(ToInt32(rhs)), ToRegister(dest), SetCond);
|
||||
masm.ma_add(ToRegister(lhs), Imm32(ToInt32(rhs)), ToRegister(dest), SetCC);
|
||||
else
|
||||
masm.ma_add(ToRegister(lhs), ToOperand(rhs), ToRegister(dest), SetCond);
|
||||
masm.ma_add(ToRegister(lhs), ToOperand(rhs), ToRegister(dest), SetCC);
|
||||
|
||||
if (ins->snapshot())
|
||||
bailoutIf(Assembler::Overflow, ins->snapshot());
|
||||
@@ -398,9 +398,9 @@ CodeGeneratorARM::visitSubI(LSubI* ins)
|
||||
const LDefinition* dest = ins->getDef(0);
|
||||
|
||||
if (rhs->isConstant())
|
||||
masm.ma_sub(ToRegister(lhs), Imm32(ToInt32(rhs)), ToRegister(dest), SetCond);
|
||||
masm.ma_sub(ToRegister(lhs), Imm32(ToInt32(rhs)), ToRegister(dest), SetCC);
|
||||
else
|
||||
masm.ma_sub(ToRegister(lhs), ToOperand(rhs), ToRegister(dest), SetCond);
|
||||
masm.ma_sub(ToRegister(lhs), ToOperand(rhs), ToRegister(dest), SetCC);
|
||||
|
||||
if (ins->snapshot())
|
||||
bailoutIf(Assembler::Overflow, ins->snapshot());
|
||||
@@ -428,7 +428,7 @@ CodeGeneratorARM::visitMulI(LMulI* ins)
|
||||
// TODO: move these to ma_mul.
|
||||
switch (constant) {
|
||||
case -1:
|
||||
masm.ma_rsb(ToRegister(lhs), Imm32(0), ToRegister(dest), SetCond);
|
||||
masm.ma_rsb(ToRegister(lhs), Imm32(0), ToRegister(dest), SetCC);
|
||||
break;
|
||||
case 0:
|
||||
masm.ma_mov(Imm32(0), ToRegister(dest));
|
||||
@@ -438,7 +438,7 @@ CodeGeneratorARM::visitMulI(LMulI* ins)
|
||||
masm.ma_mov(ToRegister(lhs), ToRegister(dest));
|
||||
return; // Escape overflow check;
|
||||
case 2:
|
||||
masm.ma_add(ToRegister(lhs), ToRegister(lhs), ToRegister(dest), SetCond);
|
||||
masm.ma_add(ToRegister(lhs), ToRegister(lhs), ToRegister(dest), SetCC);
|
||||
// Overflow is handled later.
|
||||
break;
|
||||
default: {
|
||||
@@ -648,7 +648,7 @@ CodeGeneratorARM::visitDivPowTwoI(LDivPowTwoI* ins)
|
||||
MDiv* mir = ins->mir();
|
||||
if (!mir->isTruncated()) {
|
||||
// If the remainder is != 0, bailout since this must be a double.
|
||||
masm.as_mov(ScratchRegister, lsl(lhs, 32 - shift), SetCond);
|
||||
masm.as_mov(ScratchRegister, lsl(lhs, 32 - shift), SetCC);
|
||||
bailoutIf(Assembler::NonZero, ins->snapshot());
|
||||
}
|
||||
|
||||
@@ -813,11 +813,11 @@ CodeGeneratorARM::visitModPowTwoI(LModPowTwoI* ins)
|
||||
Label fin;
|
||||
// bug 739870, jbramley has a different sequence that may help with speed
|
||||
// here.
|
||||
masm.ma_mov(in, out, SetCond);
|
||||
masm.ma_mov(in, out, SetCC);
|
||||
masm.ma_b(&fin, Assembler::Zero);
|
||||
masm.ma_rsb(Imm32(0), out, NoSetCond, Assembler::Signed);
|
||||
masm.ma_rsb(Imm32(0), out, LeaveCC, Assembler::Signed);
|
||||
masm.ma_and(Imm32((1 << ins->shift()) - 1), out);
|
||||
masm.ma_rsb(Imm32(0), out, SetCond, Assembler::Signed);
|
||||
masm.ma_rsb(Imm32(0), out, SetCC, Assembler::Signed);
|
||||
if (mir->canBeNegativeDividend()) {
|
||||
if (!mir->isTruncated()) {
|
||||
MOZ_ASSERT(mir->fallible());
|
||||
@@ -1102,8 +1102,8 @@ CodeGeneratorARM::emitTableSwitchDispatch(MTableSwitch* mir, Register index, Reg
|
||||
|
||||
int32_t cases = mir->numCases();
|
||||
// Lower value with low value.
|
||||
masm.ma_sub(index, Imm32(mir->low()), index, SetCond);
|
||||
masm.ma_rsb(index, Imm32(cases - 1), index, SetCond, Assembler::NotSigned);
|
||||
masm.ma_sub(index, Imm32(mir->low()), index, SetCC);
|
||||
masm.ma_rsb(index, Imm32(cases - 1), index, SetCC, Assembler::NotSigned);
|
||||
// Inhibit pools within the following sequence because we are indexing into
|
||||
// a pc relative table. The region will have one instruction for ma_ldr, one
|
||||
// for ma_b, and each table case takes one word.
|
||||
@@ -1614,8 +1614,8 @@ CodeGeneratorARM::visitNotD(LNotD* ins)
|
||||
} else {
|
||||
masm.as_vmrs(pc);
|
||||
masm.ma_mov(Imm32(0), dest);
|
||||
masm.ma_mov(Imm32(1), dest, NoSetCond, Assembler::Equal);
|
||||
masm.ma_mov(Imm32(1), dest, NoSetCond, Assembler::Overflow);
|
||||
masm.ma_mov(Imm32(1), dest, LeaveCC, Assembler::Equal);
|
||||
masm.ma_mov(Imm32(1), dest, LeaveCC, Assembler::Overflow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1642,8 +1642,8 @@ CodeGeneratorARM::visitNotF(LNotF* ins)
|
||||
} else {
|
||||
masm.as_vmrs(pc);
|
||||
masm.ma_mov(Imm32(0), dest);
|
||||
masm.ma_mov(Imm32(1), dest, NoSetCond, Assembler::Equal);
|
||||
masm.ma_mov(Imm32(1), dest, NoSetCond, Assembler::Overflow);
|
||||
masm.ma_mov(Imm32(1), dest, LeaveCC, Assembler::Equal);
|
||||
masm.ma_mov(Imm32(1), dest, LeaveCC, Assembler::Overflow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1795,9 +1795,9 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
|
||||
if (isFloat) {
|
||||
VFPRegister vd(ToFloatRegister(ins->output()));
|
||||
if (size == 32)
|
||||
masm.ma_vldr(Operand(HeapReg, ptrImm), vd.singleOverlay(), Assembler::Always);
|
||||
masm.ma_vldr(Address(HeapReg, ptrImm), vd.singleOverlay(), Assembler::Always);
|
||||
else
|
||||
masm.ma_vldr(Operand(HeapReg, ptrImm), vd, Assembler::Always);
|
||||
masm.ma_vldr(Address(HeapReg, ptrImm), vd, Assembler::Always);
|
||||
} else {
|
||||
masm.ma_dataTransferN(IsLoad, size, isSigned, HeapReg, Imm32(ptrImm),
|
||||
ToRegister(ins->output()), Offset, Assembler::Always);
|
||||
@@ -1828,17 +1828,17 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
|
||||
FloatRegister dst = ToFloatRegister(ins->output());
|
||||
VFPRegister vd(dst);
|
||||
if (size == 32) {
|
||||
masm.ma_vldr(Operand(GlobalReg, AsmJSNaN32GlobalDataOffset - AsmJSGlobalRegBias),
|
||||
masm.ma_vldr(Address(GlobalReg, AsmJSNaN32GlobalDataOffset - AsmJSGlobalRegBias),
|
||||
vd.singleOverlay(), Assembler::AboveOrEqual);
|
||||
masm.ma_vldr(vd.singleOverlay(), HeapReg, ptrReg, 0, Assembler::Below);
|
||||
} else {
|
||||
masm.ma_vldr(Operand(GlobalReg, AsmJSNaN64GlobalDataOffset - AsmJSGlobalRegBias),
|
||||
masm.ma_vldr(Address(GlobalReg, AsmJSNaN64GlobalDataOffset - AsmJSGlobalRegBias),
|
||||
vd, Assembler::AboveOrEqual);
|
||||
masm.ma_vldr(vd, HeapReg, ptrReg, 0, Assembler::Below);
|
||||
}
|
||||
} else {
|
||||
Register d = ToRegister(ins->output());
|
||||
masm.ma_mov(Imm32(0), d, NoSetCond, Assembler::AboveOrEqual);
|
||||
masm.ma_mov(Imm32(0), d, LeaveCC, Assembler::AboveOrEqual);
|
||||
masm.ma_dataTransferN(IsLoad, size, isSigned, HeapReg, ptrReg, d, Offset, Assembler::Below);
|
||||
}
|
||||
memoryBarrier(mir->barrierAfter());
|
||||
@@ -1872,9 +1872,9 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins)
|
||||
if (isFloat) {
|
||||
VFPRegister vd(ToFloatRegister(ins->value()));
|
||||
if (size == 32)
|
||||
masm.ma_vstr(vd.singleOverlay(), Operand(HeapReg, ptrImm), Assembler::Always);
|
||||
masm.ma_vstr(vd.singleOverlay(), Address(HeapReg, ptrImm), Assembler::Always);
|
||||
else
|
||||
masm.ma_vstr(vd, Operand(HeapReg, ptrImm), Assembler::Always);
|
||||
masm.ma_vstr(vd, Address(HeapReg, ptrImm), Assembler::Always);
|
||||
} else {
|
||||
masm.ma_dataTransferN(IsStore, size, isSigned, HeapReg, Imm32(ptrImm),
|
||||
ToRegister(ins->value()), Offset, Assembler::Always);
|
||||
@@ -2091,7 +2091,7 @@ void
|
||||
CodeGeneratorARM::visitAsmJSPassStackArg(LAsmJSPassStackArg* ins)
|
||||
{
|
||||
const MAsmJSPassStackArg* mir = ins->mir();
|
||||
Operand dst(StackPointer, mir->spOffset());
|
||||
Address dst(StackPointer, mir->spOffset());
|
||||
if (ins->arg()->isConstant()) {
|
||||
//masm.as_bkpt();
|
||||
masm.ma_storeImm(Imm32(ToInt32(ins->arg())), dst);
|
||||
@@ -2233,9 +2233,9 @@ CodeGeneratorARM::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins)
|
||||
masm.ma_dtr(IsLoad, GlobalReg, Imm32(addr), ToRegister(ins->output()));
|
||||
} else if (mir->type() == MIRType_Float32) {
|
||||
VFPRegister vd(ToFloatRegister(ins->output()));
|
||||
masm.ma_vldr(Operand(GlobalReg, addr), vd.singleOverlay());
|
||||
masm.ma_vldr(Address(GlobalReg, addr), vd.singleOverlay());
|
||||
} else {
|
||||
masm.ma_vldr(Operand(GlobalReg, addr), ToFloatRegister(ins->output()));
|
||||
masm.ma_vldr(Address(GlobalReg, addr), ToFloatRegister(ins->output()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2252,9 +2252,9 @@ CodeGeneratorARM::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins)
|
||||
masm.ma_dtr(IsStore, GlobalReg, Imm32(addr), ToRegister(ins->value()));
|
||||
} else if (type == MIRType_Float32) {
|
||||
VFPRegister vd(ToFloatRegister(ins->value()));
|
||||
masm.ma_vstr(vd.singleOverlay(), Operand(GlobalReg, addr));
|
||||
masm.ma_vstr(vd.singleOverlay(), Address(GlobalReg, addr));
|
||||
} else {
|
||||
masm.ma_vstr(ToFloatRegister(ins->value()), Operand(GlobalReg, addr));
|
||||
masm.ma_vstr(ToFloatRegister(ins->value()), Address(GlobalReg, addr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2277,7 +2277,7 @@ CodeGeneratorARM::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins)
|
||||
{
|
||||
const MAsmJSLoadFFIFunc* mir = ins->mir();
|
||||
|
||||
masm.ma_ldr(Operand(GlobalReg, mir->globalDataOffset() - AsmJSGlobalRegBias),
|
||||
masm.ma_ldr(Address(GlobalReg, mir->globalDataOffset() - AsmJSGlobalRegBias),
|
||||
ToRegister(ins->output()));
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+101
-110
@@ -40,21 +40,29 @@ class MacroAssemblerARM : public Assembler
|
||||
|
||||
public:
|
||||
// Higher level tag testing code.
|
||||
Operand ToPayload(Operand base) {
|
||||
// TODO: Can probably remove the Operand versions.
|
||||
Operand ToPayload(Operand base) const {
|
||||
return Operand(Register::FromCode(base.base()), base.disp());
|
||||
}
|
||||
Address ToPayload(Address base) {
|
||||
return ToPayload(Operand(base)).toAddress();
|
||||
Address ToPayload(const Address& base) const {
|
||||
return base;
|
||||
}
|
||||
|
||||
protected:
|
||||
Operand ToType(Operand base) {
|
||||
Operand ToType(Operand base) const {
|
||||
return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void*));
|
||||
}
|
||||
Address ToType(Address base) {
|
||||
Address ToType(const Address& base) const {
|
||||
return ToType(Operand(base)).toAddress();
|
||||
}
|
||||
|
||||
Address ToPayloadAfterStackPush(const Address& base) const {
|
||||
// If we are based on StackPointer, pass over the type tag just pushed.
|
||||
if (base.base == StackPointer)
|
||||
return Address(base.base, base.offset + sizeof(void *));
|
||||
return ToPayload(base);
|
||||
}
|
||||
|
||||
public:
|
||||
MacroAssemblerARM()
|
||||
: secondScratchReg_(lr)
|
||||
@@ -68,6 +76,7 @@ class MacroAssemblerARM : public Assembler
|
||||
void convertBoolToInt32(Register source, Register dest);
|
||||
void convertInt32ToDouble(Register src, FloatRegister dest);
|
||||
void convertInt32ToDouble(const Address& src, FloatRegister dest);
|
||||
void convertInt32ToDouble(const BaseIndex& src, FloatRegister dest);
|
||||
void convertUInt32ToFloat32(Register src, FloatRegister dest);
|
||||
void convertUInt32ToDouble(Register src, FloatRegister dest);
|
||||
void convertDoubleToFloat32(FloatRegister src, FloatRegister dest,
|
||||
@@ -96,17 +105,17 @@ class MacroAssemblerARM : public Assembler
|
||||
// instructions.
|
||||
private:
|
||||
bool alu_dbl(Register src1, Imm32 imm, Register dest, ALUOp op,
|
||||
SetCond_ sc, Condition c);
|
||||
SBit s, Condition c);
|
||||
|
||||
public:
|
||||
void ma_alu(Register src1, Operand2 op2, Register dest, ALUOp op,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_alu(Register src1, Imm32 imm, Register dest,
|
||||
ALUOp op,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_alu(Register src1, Operand op2, Register dest, ALUOp op,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_nop();
|
||||
|
||||
void ma_movPatchable(Imm32 imm, Register dest, Assembler::Condition c,
|
||||
@@ -126,12 +135,12 @@ class MacroAssemblerARM : public Assembler
|
||||
// ALU based ops
|
||||
// mov
|
||||
void ma_mov(Register src, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_mov(Imm32 imm, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_mov(ImmWord imm, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_mov(ImmGCPtr ptr, Register dest);
|
||||
|
||||
@@ -150,98 +159,98 @@ class MacroAssemblerARM : public Assembler
|
||||
|
||||
// Move not (dest <- ~src)
|
||||
void ma_mvn(Imm32 imm, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
|
||||
void ma_mvn(Register src1, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
// Negate (dest <- -src) implemented as rsb dest, src, 0
|
||||
void ma_neg(Register src, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
// And
|
||||
void ma_and(Register src, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_and(Register src1, Register src2, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_and(Imm32 imm, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_and(Imm32 imm, Register src1, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
|
||||
|
||||
// Bit clear (dest <- dest & ~imm) or (dest <- src1 & ~src2)
|
||||
void ma_bic(Imm32 imm, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
// Exclusive or
|
||||
void ma_eor(Register src, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_eor(Register src1, Register src2, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_eor(Imm32 imm, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_eor(Imm32 imm, Register src1, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
|
||||
// Or
|
||||
void ma_orr(Register src, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_orr(Register src1, Register src2, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_orr(Imm32 imm, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
void ma_orr(Imm32 imm, Register src1, Register dest,
|
||||
SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
|
||||
// Arithmetic based ops.
|
||||
// Add with carry:
|
||||
void ma_adc(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_adc(Register src, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_adc(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_adc(Imm32 imm, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_adc(Register src, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_adc(Register src1, Register src2, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
// Add:
|
||||
void ma_add(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_add(Register src1, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_add(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_add(Register src1, Operand op, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_add(Register src1, Imm32 op, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_add(Imm32 imm, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_add(Register src1, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_add(Register src1, Register src2, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_add(Register src1, Operand op, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_add(Register src1, Imm32 op, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
// Subtract with carry:
|
||||
void ma_sbc(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_sbc(Register src1, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_sbc(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_sbc(Imm32 imm, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_sbc(Register src1, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_sbc(Register src1, Register src2, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
// Subtract:
|
||||
void ma_sub(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_sub(Register src1, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_sub(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_sub(Register src1, Operand op, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_sub(Register src1, Imm32 op, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_sub(Imm32 imm, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_sub(Register src1, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_sub(Register src1, Register src2, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_sub(Register src1, Operand op, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_sub(Register src1, Imm32 op, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
// Reverse subtract:
|
||||
void ma_rsb(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_rsb(Register src1, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_rsb(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_rsb(Register src1, Imm32 op2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_rsb(Imm32 imm, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_rsb(Register src1, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_rsb(Register src1, Register src2, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_rsb(Register src1, Imm32 op2, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
// Reverse subtract with carry:
|
||||
void ma_rsc(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_rsc(Register src1, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_rsc(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
|
||||
void ma_rsc(Imm32 imm, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_rsc(Register src1, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
void ma_rsc(Register src1, Register src2, Register dest, SBit s = LeaveCC, Condition c = Always);
|
||||
|
||||
// Compares/tests.
|
||||
// Compare negative (sets condition codes as src1 + src2 would):
|
||||
@@ -299,11 +308,11 @@ class MacroAssemblerARM : public Assembler
|
||||
|
||||
|
||||
void ma_str(Register rt, DTRAddr addr, Index mode = Offset, Condition cc = Always);
|
||||
void ma_str(Register rt, const Operand& addr, Index mode = Offset, Condition cc = Always);
|
||||
void ma_dtr(LoadStore ls, Register rt, const Operand& addr, Index mode, Condition cc);
|
||||
void ma_str(Register rt, const Address& addr, Index mode = Offset, Condition cc = Always);
|
||||
void ma_dtr(LoadStore ls, Register rt, const Address& addr, Index mode, Condition cc);
|
||||
|
||||
void ma_ldr(DTRAddr addr, Register rt, Index mode = Offset, Condition cc = Always);
|
||||
void ma_ldr(const Operand& addr, Register rt, Index mode = Offset, Condition cc = Always);
|
||||
void ma_ldr(const Address& addr, Register rt, Index mode = Offset, Condition cc = Always);
|
||||
|
||||
void ma_ldrb(DTRAddr addr, Register rt, Index mode = Offset, Condition cc = Always);
|
||||
void ma_ldrh(EDtrAddr addr, Register rt, Index mode = Offset, Condition cc = Always);
|
||||
@@ -397,15 +406,15 @@ class MacroAssemblerARM : public Assembler
|
||||
|
||||
void ma_vxfer(Register src1, Register src2, FloatRegister dest, Condition cc = Always);
|
||||
|
||||
BufferOffset ma_vdtr(LoadStore ls, const Operand& addr, VFPRegister dest, Condition cc = Always);
|
||||
BufferOffset ma_vdtr(LoadStore ls, const Address& addr, VFPRegister dest, Condition cc = Always);
|
||||
|
||||
|
||||
BufferOffset ma_vldr(VFPAddr addr, VFPRegister dest, Condition cc = Always);
|
||||
BufferOffset ma_vldr(const Operand& addr, VFPRegister dest, Condition cc = Always);
|
||||
BufferOffset ma_vldr(const Address& addr, VFPRegister dest, Condition cc = Always);
|
||||
BufferOffset ma_vldr(VFPRegister src, Register base, Register index, int32_t shift = defaultShift, Condition cc = Always);
|
||||
|
||||
BufferOffset ma_vstr(VFPRegister src, VFPAddr addr, Condition cc = Always);
|
||||
BufferOffset ma_vstr(VFPRegister src, const Operand& addr, Condition cc = Always);
|
||||
BufferOffset ma_vstr(VFPRegister src, const Address& addr, Condition cc = Always);
|
||||
|
||||
BufferOffset ma_vstr(VFPRegister src, Register base, Register index, int32_t shift,
|
||||
int32_t offset, Condition cc = Always);
|
||||
@@ -501,7 +510,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
// use between one and three slots depending on its size and alignment
|
||||
// requirements.
|
||||
uint32_t usedIntSlots_;
|
||||
#if defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_ARM_SIMULATOR)
|
||||
#if defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_SIMULATOR_ARM)
|
||||
uint32_t usedFloatSlots_;
|
||||
bool usedFloat32_;
|
||||
uint32_t padding_;
|
||||
@@ -634,11 +643,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
ma_mov(imm, ScratchRegister);
|
||||
ma_push(ScratchRegister);
|
||||
}
|
||||
void push(ImmMaybeNurseryPtr imm) {
|
||||
push(noteMaybeNurseryPtr(imm));
|
||||
}
|
||||
void push(const Address& address) {
|
||||
ma_ldr(Operand(address.base, address.offset), ScratchRegister);
|
||||
void push(const Address& addr) {
|
||||
ma_ldr(addr, ScratchRegister);
|
||||
ma_push(ScratchRegister);
|
||||
}
|
||||
void push(Register reg) {
|
||||
@@ -701,16 +707,16 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
void jump(Register reg) {
|
||||
ma_bx(reg);
|
||||
}
|
||||
void jump(const Address& address) {
|
||||
ma_ldr(Operand(address.base, address.offset), ScratchRegister);
|
||||
void jump(const Address& addr) {
|
||||
ma_ldr(addr, ScratchRegister);
|
||||
ma_bx(ScratchRegister);
|
||||
}
|
||||
|
||||
void neg32(Register reg) {
|
||||
ma_neg(reg, reg, SetCond);
|
||||
ma_neg(reg, reg, SetCC);
|
||||
}
|
||||
void negl(Register reg) {
|
||||
ma_neg(reg, reg, SetCond);
|
||||
ma_neg(reg, reg, SetCC);
|
||||
}
|
||||
void test32(Register lhs, Register rhs) {
|
||||
ma_tst(lhs, rhs);
|
||||
@@ -718,8 +724,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
void test32(Register lhs, Imm32 imm) {
|
||||
ma_tst(lhs, imm);
|
||||
}
|
||||
void test32(const Address& address, Imm32 imm) {
|
||||
ma_ldr(Operand(address.base, address.offset), ScratchRegister);
|
||||
void test32(const Address& addr, Imm32 imm) {
|
||||
ma_ldr(addr, ScratchRegister);
|
||||
ma_tst(ScratchRegister, imm);
|
||||
}
|
||||
void testPtr(Register lhs, Register rhs) {
|
||||
@@ -845,7 +851,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
|
||||
void boolValueToDouble(const ValueOperand& operand, FloatRegister dest);
|
||||
void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest);
|
||||
void loadInt32OrDouble(const Operand& src, FloatRegister dest);
|
||||
void loadInt32OrDouble(const Address& src, FloatRegister dest);
|
||||
void loadInt32OrDouble(Register base, Register index,
|
||||
FloatRegister dest, int32_t shift = defaultShift);
|
||||
void loadConstantDouble(double dp, FloatRegister dest);
|
||||
@@ -881,7 +887,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
if (lhs.getTag() == Operand::OP2) {
|
||||
branch32(cond, lhs.toReg(), rhs, label);
|
||||
} else {
|
||||
ma_ldr(lhs, ScratchRegister);
|
||||
ma_ldr(lhs.toAddress(), ScratchRegister);
|
||||
branch32(cond, ScratchRegister, rhs, label);
|
||||
}
|
||||
}
|
||||
@@ -890,7 +896,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
branch32(cond, lhs.toReg(), rhs, label);
|
||||
} else {
|
||||
// branch32 will use ScratchRegister.
|
||||
ma_ldr(lhs, secondScratchReg_);
|
||||
ma_ldr(lhs.toAddress(), secondScratchReg_);
|
||||
branch32(cond, secondScratchReg_, rhs, label);
|
||||
}
|
||||
}
|
||||
@@ -1065,9 +1071,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
ma_cmp(secondScratchReg_, ptr);
|
||||
ma_b(label, cond);
|
||||
}
|
||||
void branchPtr(Condition cond, Address addr, ImmMaybeNurseryPtr ptr, Label* label) {
|
||||
branchPtr(cond, addr, noteMaybeNurseryPtr(ptr), label);
|
||||
}
|
||||
void branchPtr(Condition cond, Address addr, ImmWord ptr, Label* label) {
|
||||
ma_ldr(addr, secondScratchReg_);
|
||||
ma_cmp(secondScratchReg_, ptr);
|
||||
@@ -1109,7 +1112,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
|
||||
void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) {
|
||||
if (dest.isFloat())
|
||||
loadInt32OrDouble(Operand(address), dest.fpu());
|
||||
loadInt32OrDouble(address, dest.fpu());
|
||||
else
|
||||
ma_ldr(address, dest.gpr());
|
||||
}
|
||||
@@ -1167,29 +1170,26 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
ma_mov(s1, d1);
|
||||
}
|
||||
|
||||
void storeValue(ValueOperand val, Operand dst);
|
||||
void storeValue(ValueOperand val, const Address& dst);
|
||||
void storeValue(ValueOperand val, const BaseIndex& dest);
|
||||
void storeValue(JSValueType type, Register reg, BaseIndex dest) {
|
||||
ma_alu(dest.base, lsl(dest.index, dest.scale), ScratchRegister, OpAdd);
|
||||
storeValue(type, reg, Address(ScratchRegister, dest.offset));
|
||||
}
|
||||
void storeValue(ValueOperand val, const Address& dest) {
|
||||
storeValue(val, Operand(dest));
|
||||
}
|
||||
void storeValue(JSValueType type, Register reg, Address dest) {
|
||||
ma_str(reg, dest);
|
||||
ma_mov(ImmTag(JSVAL_TYPE_TO_TAG(type)), secondScratchReg_);
|
||||
ma_str(secondScratchReg_, Address(dest.base, dest.offset + 4));
|
||||
}
|
||||
void storeValue(const Value& val, Address dest) {
|
||||
void storeValue(const Value& val, const Address& dest) {
|
||||
jsval_layout jv = JSVAL_TO_IMPL(val);
|
||||
ma_mov(Imm32(jv.s.tag), secondScratchReg_);
|
||||
ma_str(secondScratchReg_, Address(dest.base, dest.offset + 4));
|
||||
ma_str(secondScratchReg_, ToType(dest));
|
||||
if (val.isMarkable())
|
||||
ma_mov(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())), secondScratchReg_);
|
||||
else
|
||||
ma_mov(Imm32(jv.s.payload.i32), secondScratchReg_);
|
||||
ma_str(secondScratchReg_, dest);
|
||||
ma_str(secondScratchReg_, ToPayload(dest));
|
||||
}
|
||||
void storeValue(const Value& val, BaseIndex dest) {
|
||||
ma_alu(dest.base, lsl(dest.index, dest.scale), ScratchRegister, OpAdd);
|
||||
@@ -1209,7 +1209,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
jsval_layout jv = JSVAL_TO_IMPL(val);
|
||||
push(Imm32(jv.s.tag));
|
||||
if (val.isMarkable())
|
||||
push(ImmMaybeNurseryPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())));
|
||||
push(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())));
|
||||
else
|
||||
push(Imm32(jv.s.payload.i32));
|
||||
}
|
||||
@@ -1217,13 +1217,13 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
|
||||
ma_push(reg);
|
||||
}
|
||||
void pushValue(const Address &addr);
|
||||
void pushValue(const Address& addr);
|
||||
|
||||
void storePayload(const Value &val, Operand dest);
|
||||
void storePayload(Register src, Operand dest);
|
||||
void storePayload(const Value &val, const BaseIndex &dest);
|
||||
void storePayload(const Value& val, const Address& dest);
|
||||
void storePayload(Register src, const Address& dest);
|
||||
void storePayload(const Value& val, const BaseIndex& dest);
|
||||
void storePayload(Register src, const BaseIndex& dest);
|
||||
void storeTypeTag(ImmTag tag, Operand dest);
|
||||
void storeTypeTag(ImmTag tag, const Address& dest);
|
||||
void storeTypeTag(ImmTag tag, const BaseIndex& dest);
|
||||
|
||||
void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
|
||||
@@ -1292,7 +1292,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
void movePtr(ImmPtr imm, Register dest);
|
||||
void movePtr(AsmJSImmPtr imm, Register dest);
|
||||
void movePtr(ImmGCPtr imm, Register dest);
|
||||
void movePtr(ImmMaybeNurseryPtr imm, Register dest);
|
||||
|
||||
void load8SignExtend(const Address& address, Register dest);
|
||||
void load8SignExtend(const BaseIndex& src, Register dest);
|
||||
@@ -1382,7 +1381,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
void storePtr(Register src, const BaseIndex& address);
|
||||
void storePtr(Register src, AbsoluteAddress dest);
|
||||
void storeDouble(FloatRegister src, Address addr) {
|
||||
ma_vstr(src, Operand(addr));
|
||||
ma_vstr(src, addr);
|
||||
}
|
||||
void storeDouble(FloatRegister src, BaseIndex addr) {
|
||||
uint32_t scale = Imm32::ShiftOf(addr.scale).value;
|
||||
@@ -1392,10 +1391,10 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
ma_vmov(src, dest);
|
||||
}
|
||||
|
||||
void storeFloat32(FloatRegister src, Address addr) {
|
||||
ma_vstr(VFPRegister(src).singleOverlay(), Operand(addr));
|
||||
void storeFloat32(FloatRegister src, const Address& addr) {
|
||||
ma_vstr(VFPRegister(src).singleOverlay(), addr);
|
||||
}
|
||||
void storeFloat32(FloatRegister src, BaseIndex addr) {
|
||||
void storeFloat32(FloatRegister src, const BaseIndex& addr) {
|
||||
uint32_t scale = Imm32::ShiftOf(addr.scale).value;
|
||||
ma_vstr(VFPRegister(src).singleOverlay(), addr.base, addr.index, scale, addr.offset);
|
||||
}
|
||||
@@ -1641,9 +1640,9 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
void clampIntToUint8(Register reg) {
|
||||
// Look at (reg >> 8) if it is 0, then reg shouldn't be clamped if it is
|
||||
// <0, then we want to clamp to 0, otherwise, we wish to clamp to 255
|
||||
as_mov(ScratchRegister, asr(reg, 8), SetCond);
|
||||
ma_mov(Imm32(0xff), reg, NoSetCond, NotEqual);
|
||||
ma_mov(Imm32(0), reg, NoSetCond, Signed);
|
||||
as_mov(ScratchRegister, asr(reg, 8), SetCC);
|
||||
ma_mov(Imm32(0xff), reg, LeaveCC, NotEqual);
|
||||
ma_mov(Imm32(0), reg, LeaveCC, Signed);
|
||||
}
|
||||
|
||||
void incrementInt32Value(const Address& addr) {
|
||||
@@ -1721,7 +1720,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
emitSet(Assembler::Condition cond, Register dest)
|
||||
{
|
||||
ma_mov(Imm32(0), dest);
|
||||
ma_mov(Imm32(1), dest, NoSetCond, cond);
|
||||
ma_mov(Imm32(1), dest, LeaveCC, cond);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
@@ -1798,12 +1797,12 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
}
|
||||
|
||||
void computeEffectiveAddress(const Address& address, Register dest) {
|
||||
ma_add(address.base, Imm32(address.offset), dest, NoSetCond);
|
||||
ma_add(address.base, Imm32(address.offset), dest, LeaveCC);
|
||||
}
|
||||
void computeEffectiveAddress(const BaseIndex& address, Register dest) {
|
||||
ma_alu(address.base, lsl(address.index, address.scale), dest, OpAdd, NoSetCond);
|
||||
ma_alu(address.base, lsl(address.index, address.scale), dest, OpAdd, LeaveCC);
|
||||
if (address.offset)
|
||||
ma_add(dest, Imm32(address.offset), dest, NoSetCond);
|
||||
ma_add(dest, Imm32(address.offset), dest, LeaveCC);
|
||||
}
|
||||
void floor(FloatRegister input, Register output, Label* handleNotAnInt);
|
||||
void floorf(FloatRegister input, Register output, Label* handleNotAnInt);
|
||||
@@ -1840,19 +1839,11 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
ma_add(addr.baseReg(), Imm32(addr.disp()), dest);
|
||||
}
|
||||
|
||||
void stackCheck(ImmWord limitAddr, Label* label) {
|
||||
int* foo = 0;
|
||||
*foo = 5;
|
||||
movePtr(limitAddr, ScratchRegister);
|
||||
ma_ldr(Address(ScratchRegister, 0), ScratchRegister);
|
||||
ma_cmp(ScratchRegister, StackPointer);
|
||||
ma_b(label, Assembler::AboveOrEqual);
|
||||
}
|
||||
void abiret() {
|
||||
as_bx(lr);
|
||||
}
|
||||
|
||||
void ma_storeImm(Imm32 c, const Operand& dest) {
|
||||
void ma_storeImm(Imm32 c, const Address& dest) {
|
||||
ma_mov(c, lr);
|
||||
ma_str(lr, dest);
|
||||
}
|
||||
|
||||
@@ -40,43 +40,36 @@ MoveEmitterARM::~MoveEmitterARM()
|
||||
assertDone();
|
||||
}
|
||||
|
||||
Operand
|
||||
Address
|
||||
MoveEmitterARM::cycleSlot(uint32_t slot, uint32_t subslot) const
|
||||
{
|
||||
int32_t offset = masm.framePushed() - pushedAtCycle_;
|
||||
MOZ_ASSERT(offset < 4096 && offset > -4096);
|
||||
return Operand(StackPointer, offset + slot * sizeof(double) + subslot);
|
||||
return Address(StackPointer, offset + slot * sizeof(double) + subslot);
|
||||
}
|
||||
|
||||
// THIS IS ALWAYS AN LDRAddr. It should not be wrapped in an operand, methinks.
|
||||
Operand
|
||||
Address
|
||||
MoveEmitterARM::spillSlot() const
|
||||
{
|
||||
int32_t offset = masm.framePushed() - pushedAtSpill_;
|
||||
MOZ_ASSERT(offset < 4096 && offset > -4096);
|
||||
return Operand(StackPointer, offset);
|
||||
return Address(StackPointer, offset);
|
||||
}
|
||||
|
||||
Operand
|
||||
MoveEmitterARM::toOperand(const MoveOperand& operand, bool isFloat) const
|
||||
Address
|
||||
MoveEmitterARM::toAddress(const MoveOperand& operand) const
|
||||
{
|
||||
if (operand.isMemoryOrEffectiveAddress()) {
|
||||
if (operand.base() != StackPointer) {
|
||||
MOZ_ASSERT(operand.disp() < 1024 && operand.disp() > -1024);
|
||||
return Operand(operand.base(), operand.disp());
|
||||
}
|
||||
MOZ_ASSERT(operand.isMemoryOrEffectiveAddress());
|
||||
|
||||
MOZ_ASSERT(operand.disp() >= 0);
|
||||
|
||||
// Otherwise, the stack offset may need to be adjusted.
|
||||
return Operand(StackPointer, operand.disp() + (masm.framePushed() - pushedAtStart_));
|
||||
if (operand.base() != StackPointer) {
|
||||
MOZ_ASSERT(operand.disp() < 1024 && operand.disp() > -1024);
|
||||
return Operand(operand.base(), operand.disp()).toAddress();
|
||||
}
|
||||
|
||||
if (operand.isGeneralReg())
|
||||
return Operand(operand.reg());
|
||||
MOZ_ASSERT(operand.disp() >= 0);
|
||||
|
||||
MOZ_ASSERT(operand.isFloatReg());
|
||||
return Operand(operand.floatReg());
|
||||
// Otherwise, the stack offset may need to be adjusted.
|
||||
return Address(StackPointer, operand.disp() + (masm.framePushed() - pushedAtStart_));
|
||||
}
|
||||
|
||||
Register
|
||||
@@ -115,7 +108,7 @@ MoveEmitterARM::breakCycle(const MoveOperand& from, const MoveOperand& to,
|
||||
case MoveOp::FLOAT32:
|
||||
if (to.isMemory()) {
|
||||
VFPRegister temp = ScratchFloat32Reg;
|
||||
masm.ma_vldr(toOperand(to, true), temp);
|
||||
masm.ma_vldr(toAddress(to), temp);
|
||||
// Since it is uncertain if the load will be aligned or not
|
||||
// just fill both of them with the same value.
|
||||
masm.ma_vstr(temp, cycleSlot(slotId, 0));
|
||||
@@ -130,7 +123,7 @@ MoveEmitterARM::breakCycle(const MoveOperand& from, const MoveOperand& to,
|
||||
case MoveOp::DOUBLE:
|
||||
if (to.isMemory()) {
|
||||
FloatRegister temp = ScratchDoubleReg;
|
||||
masm.ma_vldr(toOperand(to, true), temp);
|
||||
masm.ma_vldr(toAddress(to), temp);
|
||||
masm.ma_vstr(temp, cycleSlot(slotId, 0));
|
||||
} else {
|
||||
masm.ma_vstr(to.floatReg().doubleOverlay(), cycleSlot(slotId, 0));
|
||||
@@ -141,7 +134,7 @@ MoveEmitterARM::breakCycle(const MoveOperand& from, const MoveOperand& to,
|
||||
// an non-vfp value
|
||||
if (to.isMemory()) {
|
||||
Register temp = tempReg();
|
||||
masm.ma_ldr(toOperand(to, false), temp);
|
||||
masm.ma_ldr(toAddress(to), temp);
|
||||
masm.ma_str(temp, cycleSlot(0,0));
|
||||
} else {
|
||||
if (to.reg() == spilledReg_) {
|
||||
@@ -172,7 +165,7 @@ MoveEmitterARM::completeCycle(const MoveOperand& from, const MoveOperand& to, Mo
|
||||
if (to.isMemory()) {
|
||||
FloatRegister temp = ScratchDoubleReg;
|
||||
masm.ma_vldr(cycleSlot(slotId, 0), temp);
|
||||
masm.ma_vstr(temp, toOperand(to, true));
|
||||
masm.ma_vstr(temp, toAddress(to));
|
||||
} else {
|
||||
uint32_t offset = 0;
|
||||
if ((!from.isMemory()) && from.floatReg().numAlignedAliased() == 1)
|
||||
@@ -186,7 +179,7 @@ MoveEmitterARM::completeCycle(const MoveOperand& from, const MoveOperand& to, Mo
|
||||
if (to.isMemory()) {
|
||||
Register temp = tempReg();
|
||||
masm.ma_ldr(cycleSlot(slotId, 0), temp);
|
||||
masm.ma_str(temp, toOperand(to, false));
|
||||
masm.ma_str(temp, toAddress(to));
|
||||
} else {
|
||||
if (to.reg() == spilledReg_) {
|
||||
// Make sure we don't re-clobber the spilled register later.
|
||||
@@ -216,21 +209,14 @@ MoveEmitterARM::emitMove(const MoveOperand& from, const MoveOperand& to)
|
||||
masm.ma_ldr(spillSlot(), spilledReg_);
|
||||
spilledReg_ = InvalidReg;
|
||||
}
|
||||
switch (toOperand(to, false).getTag()) {
|
||||
case Operand::OP2:
|
||||
// secretly must be a register
|
||||
if (to.isMemoryOrEffectiveAddress())
|
||||
masm.ma_str(from.reg(), toAddress(to));
|
||||
else
|
||||
masm.ma_mov(from.reg(), to.reg());
|
||||
break;
|
||||
case Operand::MEM:
|
||||
masm.ma_str(from.reg(), toOperand(to, false));
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("strange move!");
|
||||
}
|
||||
} else if (to.isGeneralReg()) {
|
||||
MOZ_ASSERT(from.isMemoryOrEffectiveAddress());
|
||||
if (from.isMemory())
|
||||
masm.ma_ldr(toOperand(from, false), to.reg());
|
||||
masm.ma_ldr(toAddress(from), to.reg());
|
||||
else
|
||||
masm.ma_add(from.base(), Imm32(from.disp()), to.reg());
|
||||
} else {
|
||||
@@ -239,11 +225,11 @@ MoveEmitterARM::emitMove(const MoveOperand& from, const MoveOperand& to)
|
||||
|
||||
MOZ_ASSERT(from.isMemoryOrEffectiveAddress());
|
||||
if (from.isMemory())
|
||||
masm.ma_ldr(toOperand(from, false), reg);
|
||||
masm.ma_ldr(toAddress(from), reg);
|
||||
else
|
||||
masm.ma_add(from.base(), Imm32(from.disp()), reg);
|
||||
MOZ_ASSERT(to.base() != reg);
|
||||
masm.ma_str(reg, toOperand(to, false));
|
||||
masm.ma_str(reg, toAddress(to));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,19 +240,15 @@ MoveEmitterARM::emitFloat32Move(const MoveOperand& from, const MoveOperand& to)
|
||||
if (to.isFloatReg())
|
||||
masm.ma_vmov_f32(from.floatReg(), to.floatReg());
|
||||
else
|
||||
masm.ma_vstr(VFPRegister(from.floatReg()).singleOverlay(),
|
||||
toOperand(to, true));
|
||||
masm.ma_vstr(VFPRegister(from.floatReg()).singleOverlay(), toAddress(to));
|
||||
} else if (to.isFloatReg()) {
|
||||
masm.ma_vldr(toOperand(from, true),
|
||||
VFPRegister(to.floatReg()).singleOverlay());
|
||||
masm.ma_vldr(toAddress(from), VFPRegister(to.floatReg()).singleOverlay());
|
||||
} else {
|
||||
// Memory to memory move.
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
FloatRegister reg = ScratchFloat32Reg;
|
||||
masm.ma_vldr(toOperand(from, true),
|
||||
VFPRegister(reg).singleOverlay());
|
||||
masm.ma_vstr(VFPRegister(reg).singleOverlay(),
|
||||
toOperand(to, true));
|
||||
masm.ma_vldr(toAddress(from), VFPRegister(reg).singleOverlay());
|
||||
masm.ma_vstr(VFPRegister(reg).singleOverlay(), toAddress(to));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,15 +259,15 @@ MoveEmitterARM::emitDoubleMove(const MoveOperand& from, const MoveOperand& to)
|
||||
if (to.isFloatReg())
|
||||
masm.ma_vmov(from.floatReg(), to.floatReg());
|
||||
else
|
||||
masm.ma_vstr(from.floatReg(), toOperand(to, true));
|
||||
masm.ma_vstr(from.floatReg(), toAddress(to));
|
||||
} else if (to.isFloatReg()) {
|
||||
masm.ma_vldr(toOperand(from, true), to.floatReg());
|
||||
masm.ma_vldr(toAddress(from), to.floatReg());
|
||||
} else {
|
||||
// Memory to memory move.
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
FloatRegister reg = ScratchDoubleReg;
|
||||
masm.ma_vldr(toOperand(from, true), reg);
|
||||
masm.ma_vstr(reg, toOperand(to, true));
|
||||
masm.ma_vldr(toAddress(from), reg);
|
||||
masm.ma_vstr(reg, toAddress(to));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,9 @@ class MoveEmitterARM
|
||||
void assertDone();
|
||||
Register tempReg();
|
||||
FloatRegister tempFloatReg();
|
||||
Operand cycleSlot(uint32_t slot, uint32_t subslot) const;
|
||||
Operand spillSlot() const;
|
||||
Operand toOperand(const MoveOperand& operand, bool isFloat) const;
|
||||
Address cycleSlot(uint32_t slot, uint32_t subslot) const;
|
||||
Address spillSlot() const;
|
||||
Address toAddress(const MoveOperand& operand) const;
|
||||
|
||||
void emitMove(const MoveOperand& from, const MoveOperand& to);
|
||||
void emitFloat32Move(const MoveOperand& from, const MoveOperand& to);
|
||||
|
||||
@@ -692,7 +692,7 @@ ArmDebugger::debug()
|
||||
i < 8 &&
|
||||
(i % 2) == 0) {
|
||||
dvalue = getRegisterPairDoubleValue(i);
|
||||
printf(" (%f)\n", dvalue);
|
||||
printf(" (%.16g)\n", dvalue);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
@@ -700,7 +700,7 @@ ArmDebugger::debug()
|
||||
for (uint32_t i = 0; i < FloatRegisters::TotalPhys; i++) {
|
||||
dvalue = getVFPDoubleRegisterValue(i);
|
||||
uint64_t as_words = mozilla::BitwiseCast<uint64_t>(dvalue);
|
||||
printf("%3s: %f 0x%08x %08x\n",
|
||||
printf("%3s: %.16g 0x%08x %08x\n",
|
||||
FloatRegister::FromCode(i).name(),
|
||||
dvalue,
|
||||
static_cast<uint32_t>(as_words >> 32),
|
||||
@@ -711,7 +711,7 @@ ArmDebugger::debug()
|
||||
printf("%s: 0x%08x %d \n", arg1, value, value);
|
||||
} else if (getVFPDoubleValue(arg1, &dvalue)) {
|
||||
uint64_t as_words = mozilla::BitwiseCast<uint64_t>(dvalue);
|
||||
printf("%s: %f 0x%08x %08x\n",
|
||||
printf("%s: %.16g 0x%08x %08x\n",
|
||||
arg1,
|
||||
dvalue,
|
||||
static_cast<uint32_t>(as_words >> 32),
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#ifndef jit_arm_Simulator_arm_h
|
||||
#define jit_arm_Simulator_arm_h
|
||||
|
||||
#ifdef JS_ARM_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM
|
||||
|
||||
#include "jslock.h"
|
||||
|
||||
@@ -441,6 +441,6 @@ class Simulator
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
#endif /* JS_ARM_SIMULATOR */
|
||||
#endif /* JS_SIMULATOR_ARM */
|
||||
|
||||
#endif /* jit_arm_Simulator_arm_h */
|
||||
|
||||
@@ -183,7 +183,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
||||
|
||||
// Get a copy of the number of args to use as a decrement counter, also set
|
||||
// the zero condition code.
|
||||
aasm->as_mov(r5, O2Reg(r1), SetCond);
|
||||
aasm->as_mov(r5, O2Reg(r1), SetCC);
|
||||
|
||||
// Loop over arguments, copying them from an unknown buffer onto the Ion
|
||||
// stack so they can be accessed from JIT'ed code.
|
||||
@@ -193,7 +193,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
||||
aasm->as_b(&footer, Assembler::Zero);
|
||||
// Get the top of the loop.
|
||||
masm.bind(&header);
|
||||
aasm->as_sub(r5, r5, Imm8(1), SetCond);
|
||||
aasm->as_sub(r5, r5, Imm8(1), SetCC);
|
||||
// We could be more awesome, and unroll this, using a loadm
|
||||
// (particularly since the offset is effectively 0) but that seems more
|
||||
// error prone, and complex.
|
||||
@@ -502,7 +502,7 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
|
||||
Label undefLoopTop;
|
||||
masm.bind(&undefLoopTop);
|
||||
masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex);
|
||||
masm.ma_sub(r2, Imm32(1), r2, SetCond);
|
||||
masm.ma_sub(r2, Imm32(1), r2, SetCC);
|
||||
|
||||
masm.ma_b(&undefLoopTop, Assembler::NonZero);
|
||||
}
|
||||
@@ -514,7 +514,7 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
|
||||
masm.ma_dataTransferN(IsLoad, 64, true, r3, Imm32(-8), r4, PostIndex);
|
||||
masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex);
|
||||
|
||||
masm.ma_sub(r8, Imm32(1), r8, SetCond);
|
||||
masm.ma_sub(r8, Imm32(1), r8, SetCC);
|
||||
masm.ma_b(©LoopTop, Assembler::NotSigned);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "jit/SharedIC.h"
|
||||
#include "jit/SharedICHelpers.h"
|
||||
|
||||
#ifdef JS_ARM64_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
#include "jit/arm64/Assembler-arm64.h"
|
||||
#include "jit/arm64/BaselineCompiler-arm64.h"
|
||||
#include "jit/arm64/vixl/Debugger-vixl.h"
|
||||
|
||||
@@ -388,7 +388,7 @@ MacroAssemblerCompat::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
// no other work needs to be done.
|
||||
}
|
||||
|
||||
#if defined(DEBUG) && defined(JS_ARM64_SIMULATOR)
|
||||
#if defined(DEBUG) && defined(JS_SIMULATOR_ARM64)
|
||||
static void
|
||||
AssertValidABIFunctionType(uint32_t passedArgTypes)
|
||||
{
|
||||
@@ -418,12 +418,12 @@ AssertValidABIFunctionType(uint32_t passedArgTypes)
|
||||
MOZ_CRASH("Unexpected type");
|
||||
}
|
||||
}
|
||||
#endif // DEBUG && JS_ARM64_SIMULATOR
|
||||
#endif // DEBUG && JS_SIMULATOR_ARM64
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::callWithABI(void* fun, MoveOp::Type result)
|
||||
{
|
||||
#ifdef JS_ARM64_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
MOZ_ASSERT(passedIntArgs_ + passedFloatArgs_ <= 15);
|
||||
passedArgTypes_ <<= ArgType_Shift;
|
||||
switch (result) {
|
||||
@@ -437,7 +437,7 @@ MacroAssemblerCompat::callWithABI(void* fun, MoveOp::Type result)
|
||||
# endif
|
||||
ABIFunctionType type = ABIFunctionType(passedArgTypes_);
|
||||
fun = vixl::Simulator::RedirectNativeFunction(fun, type);
|
||||
#endif // JS_ARM64_SIMULATOR
|
||||
#endif // JS_SIMULATOR_ARM64
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
|
||||
@@ -3264,7 +3264,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
||||
|
||||
// Emits a simulator directive to save the current sp on an internal stack.
|
||||
void simulatorMarkSP() {
|
||||
#ifdef JS_ARM64_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
svc(vixl::kMarkStackPointer);
|
||||
#endif
|
||||
}
|
||||
@@ -3272,7 +3272,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
||||
// Emits a simulator directive to pop from its internal stack
|
||||
// and assert that the value is equal to the current sp.
|
||||
void simulatorCheckSP() {
|
||||
#ifdef JS_ARM64_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
svc(vixl::kCheckStackPointer);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ CPU::SetUp()
|
||||
uint32_t
|
||||
CPU::GetCacheType()
|
||||
{
|
||||
#ifdef JS_ARM64_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
// This will lead to a cache with 1 byte long lines, which is fine since the
|
||||
// simulator will not need this information.
|
||||
return 0;
|
||||
@@ -80,7 +80,7 @@ CPU::GetCacheType()
|
||||
void
|
||||
CPU::EnsureIAndDCacheCoherency(void* address, size_t length)
|
||||
{
|
||||
#ifdef JS_ARM64_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
USE(address);
|
||||
USE(length);
|
||||
#else
|
||||
@@ -162,7 +162,7 @@ CPU::EnsureIAndDCacheCoherency(void* address, size_t length)
|
||||
// isb : Instruction Synchronisation Barrier
|
||||
" isb\n"
|
||||
: : : "memory");
|
||||
#endif // JS_ARM64_SIMULATOR
|
||||
#endif // JS_SIMULATOR_ARM64
|
||||
}
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include "js-config.h"
|
||||
|
||||
#ifdef JS_ARM64_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
|
||||
#include "jit/arm64/vixl/Debugger-vixl.h"
|
||||
|
||||
@@ -1506,4 +1506,4 @@ bool InvalidCommand::Run(Debugger* debugger) {
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
#endif // JS_ARM64_SIMULATOR
|
||||
#endif // JS_SIMULATOR_ARM64
|
||||
|
||||
@@ -1222,7 +1222,7 @@ void MacroAssembler::PrintfNoPreserve(const char * format, const CPURegister& ar
|
||||
// Actually call printf. This part needs special handling for the simulator,
|
||||
// since the system printf function will use a different instruction set and
|
||||
// the procedure-call standard will not be compatible.
|
||||
#ifdef JS_ARM64_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
{
|
||||
InstructionAccurateScope scope(this, kPrintfLength / kInstructionSize);
|
||||
hlt(kPrintfOpcode);
|
||||
@@ -1319,7 +1319,7 @@ void MacroAssembler::Printf(const char * format, CPURegister arg0, CPURegister a
|
||||
|
||||
|
||||
void MacroAssembler::Trace(TraceParameters parameters, TraceCommand command) {
|
||||
#ifdef JS_ARM64_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
// The arguments to the trace pseudo instruction need to be contiguous in
|
||||
// memory, so make sure we don't try to emit a literal pool.
|
||||
InstructionAccurateScope scope(this, kTraceLength / kInstructionSize);
|
||||
@@ -1343,7 +1343,7 @@ void MacroAssembler::Trace(TraceParameters parameters, TraceCommand command) {
|
||||
|
||||
|
||||
void MacroAssembler::Log(TraceParameters parameters) {
|
||||
#ifdef JS_ARM64_SIMULATOR
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
// The arguments to the log pseudo instruction need to be contiguous in
|
||||
// memory, so make sure we don't try to emit a literal pool.
|
||||
InstructionAccurateScope scope(this, kLogLength / kInstructionSize);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user