Merge the last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-04-23 15:01:57 -04:00
commit d68fe645cf
110 changed files with 3743 additions and 3078 deletions

View File

@ -9,8 +9,9 @@
#include "nsCOMPtr.h"
#include "nsObjCExceptions.h"
#include "nsIFrame.h"
#include "nsView.h"
#include "nsIWidget.h"
#include "nsViewManager.h"
using namespace mozilla::a11y;

View File

@ -25,7 +25,7 @@ function test() {
statusText: "OK",
type: "json",
fullMimeType: "text/json; charset=utf-8",
size: L10N.getFormatStr("networkMenu.sizeKB", 83.95),
size: L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(85975/1024, 2)),
time: true
});

View File

@ -73,7 +73,7 @@ function test() {
is(responseScope.querySelector(".name").getAttribute("value"),
L10N.getStr("responseHeaders") + " (" +
L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(0.168, 3)) + ")",
L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(173/1024, 3)) + ")",
"The response headers scope doesn't have the correct title.");
ok(requestScope.querySelector(".name").getAttribute("value").contains(

View File

@ -1073,6 +1073,8 @@ conic/conicstatisticsevent.h
#endif
#if MOZ_NATIVE_LIBEVENT==1
event.h
#else
sys/event.h
#endif
#ifdef MOZ_ENABLE_LIBPROXY
proxy.h

View File

@ -6239,8 +6239,6 @@ nsDocument::GetAnimationController()
return mAnimationController;
}
static const char* dirAttributes[] = { "ltr", "rtl", "auto", 0 };
/**
* Retrieve the "direction" property of the document.
*
@ -6259,14 +6257,7 @@ nsIDocument::GetDir(nsAString& aDirection) const
aDirection.Truncate();
Element* rootElement = GetHtmlElement();
if (rootElement) {
nsAutoString dir;
rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::dir, dir);
for (uint32_t i = 0; dirAttributes[i]; ++i) {
if (dir.LowerCaseEqualsASCII(dirAttributes[i])) {
aDirection.AssignASCII(dirAttributes[i]);
return;
}
}
static_cast<nsGenericHTMLElement*>(rootElement)->GetDir(aDirection);
}
}

View File

@ -4561,7 +4561,9 @@ nsEventStateManager::CheckForAndDispatchClick(nsPresContext* aPresContext,
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
if (presShell) {
nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent);
if (!mouseContent && !mCurrentTarget) {
return NS_OK;
}
ret = presShell->HandleEventWithTarget(&event, mCurrentTarget,
mouseContent, aStatus);
if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2) {

View File

@ -377,10 +377,12 @@ ImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
target->AddEventListener(NS_LITERAL_STRING("resize"), this, false);
target->AddEventListener(NS_LITERAL_STRING("keypress"), this, false);
if (!nsContentUtils::IsChildOfSameType(this) &&
GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelImageDocument.css"));
LinkStylesheet(NS_LITERAL_STRING("chrome://global/skin/media/TopLevelImageDocument.css"));
if (GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/ImageDocument.css"));
if (!nsContentUtils::IsChildOfSameType(this)) {
LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelImageDocument.css"));
LinkStylesheet(NS_LITERAL_STRING("chrome://global/skin/media/TopLevelImageDocument.css"));
}
}
BecomeInteractive();
}
@ -810,29 +812,6 @@ ImageDocument::CreateSyntheticDocument()
nsresult rv = MediaDocument::CreateSyntheticDocument();
NS_ENSURE_SUCCESS(rv, rv);
// We must declare the image as a block element. If we stay as
// an inline element, our parent LineBox will be inline too and
// ignore the available height during reflow.
// This is bad during printing, it means tall image frames won't know
// the size of the paper and cannot break into continuations along
// multiple pages.
Element* head = GetHeadElement();
NS_ENSURE_TRUE(head, NS_ERROR_FAILURE);
nsCOMPtr<nsINodeInfo> nodeInfo;
if (nsContentUtils::IsChildOfSameType(this)) {
nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::style, nullptr,
kNameSpaceID_XHTML,
nsIDOMNode::ELEMENT_NODE);
nsRefPtr<nsGenericHTMLElement> styleContent = NS_NewHTMLStyleElement(nodeInfo.forget());
NS_ENSURE_TRUE(styleContent, NS_ERROR_OUT_OF_MEMORY);
ErrorResult error;
styleContent->SetTextContent(NS_LITERAL_STRING("img { display: block; }"),
error);
head->AppendChildTo(styleContent, false);
}
// Add the image element
Element* body = GetBodyElement();
if (!body) {
@ -840,6 +819,7 @@ ImageDocument::CreateSyntheticDocument()
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsINodeInfo> nodeInfo;
nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::img, nullptr,
kNameSpaceID_XHTML,
nsIDOMNode::ELEMENT_NODE);

View File

@ -141,6 +141,7 @@ AudioContext::CreateScriptProcessor(uint32_t aBufferSize,
nsRefPtr<ScriptProcessorNode> scriptProcessor =
new ScriptProcessorNode(this, aBufferSize, aNumberOfInputChannels,
aNumberOfOutputChannels);
mScriptProcessorNodes.AppendElement(scriptProcessor);
return scriptProcessor.forget();
}
@ -245,6 +246,12 @@ AudioContext::UnregisterPannerNode(PannerNode* aNode)
mPannerNodes.RemoveElement(aNode);
}
void
AudioContext::UnregisterScriptProcessorNode(ScriptProcessorNode* aNode)
{
mScriptProcessorNodes.RemoveElement(aNode);
}
void
AudioContext::UpdatePannerSource()
{
@ -286,6 +293,11 @@ AudioContext::Shutdown()
ErrorResult rv;
mAudioBufferSourceNodes[i]->Stop(0.0, rv);
}
// Stop all script processor nodes, to make sure that they release
// their self-references.
for (uint32_t i = 0; i < mScriptProcessorNodes.Length(); ++i) {
mScriptProcessorNodes[i]->Stop();
}
}
void

View File

@ -151,6 +151,7 @@ public:
MediaStream* DestinationStream() const;
void UnregisterAudioBufferSourceNode(AudioBufferSourceNode* aNode);
void UnregisterPannerNode(PannerNode* aNode);
void UnregisterScriptProcessorNode(ScriptProcessorNode* aNode);
void UpdatePannerSource();
JSContext* GetJSContext() const;
@ -170,6 +171,7 @@ private:
// to compute the doppler shift. Those are weak pointers.
nsTArray<PannerNode*> mPannerNodes;
nsTArray<AudioBufferSourceNode*> mAudioBufferSourceNodes;
nsTArray<ScriptProcessorNode*> mScriptProcessorNodes;
};
}

View File

@ -105,10 +105,10 @@ public:
return mContext;
}
void Connect(AudioNode& aDestination, uint32_t aOutput,
uint32_t aInput, ErrorResult& aRv);
virtual void Connect(AudioNode& aDestination, uint32_t aOutput,
uint32_t aInput, ErrorResult& aRv);
void Disconnect(uint32_t aOutput, ErrorResult& aRv);
virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv);
// The following two virtual methods must be implemented by each node type
// to provide their number of input and output ports. These numbers are

View File

@ -19,6 +19,15 @@
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ScriptProcessorNode, AudioNode)
if (tmp->Context()) {
tmp->Context()->UnregisterScriptProcessorNode(tmp);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ScriptProcessorNode, AudioNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ScriptProcessorNode)
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
@ -357,6 +366,13 @@ ScriptProcessorNode::ScriptProcessorNode(AudioContext* aContext,
engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
}
ScriptProcessorNode::~ScriptProcessorNode()
{
if (Context()) {
Context()->UnregisterScriptProcessorNode(this);
}
}
JSObject*
ScriptProcessorNode::WrapObject(JSContext* aCx, JSObject* aScope)
{

View File

@ -27,8 +27,10 @@ public:
uint32_t aBufferSize,
uint32_t aNumberOfInputChannels,
uint32_t aNumberOfOutputChannels);
virtual ~ScriptProcessorNode();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ScriptProcessorNode, AudioNode)
IMPL_EVENT_HANDLER(audioprocess)
@ -39,6 +41,23 @@ public:
return true;
}
virtual void Connect(AudioNode& aDestination, uint32_t aOutput,
uint32_t aInput, ErrorResult& aRv) MOZ_OVERRIDE
{
AudioNode::Connect(aDestination, aOutput, aInput, aRv);
if (!aRv.Failed()) {
mPlayingRef.Take(this);
}
}
virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv) MOZ_OVERRIDE
{
AudioNode::Disconnect(aOutput, aRv);
if (!aRv.Failed()) {
mPlayingRef.Drop(this);
}
}
uint32_t BufferSize() const
{
return mBufferSize;
@ -56,10 +75,16 @@ public:
using nsDOMEventTargetHelper::DispatchTrustedEvent;
void Stop()
{
mPlayingRef.Drop(this);
}
private:
nsAutoPtr<SharedBuffers> mSharedBuffers;
const uint32_t mBufferSize;
const uint32_t mNumberOfOutputChannels;
SelfReference<ScriptProcessorNode> mPlayingRef; // a reference to self while planing
};
}

View File

@ -317,6 +317,14 @@ CSRCS += \
$(NULL)
endif # }
ifdef OS_BSD # {
ifneq (,$(OS_DRAGONFLY)$(OS_FREEBSD)) # {
DEFINES += -D_EVENT_HAVE_SENDFILE
endif # }
LOCAL_INCLUDES += -I$(srcdir)/src/third_party/libevent/bsd
CSRCS += kqueue.c
endif # }
endif # }
endif # }

View File

@ -0,0 +1,455 @@
/* event2/event-config.h
*
* This file was generated by autoconf when libevent was built, and post-
* processed by Libevent so that its macros would have a uniform prefix.
*
* DO NOT EDIT THIS FILE.
*
* Do not rely on macros in this file existing in later versions.
*/
#ifndef _EVENT2_EVENT_CONFIG_H_
#define _EVENT2_EVENT_CONFIG_H_
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.in by autoheader. */
/* Define if libevent should build without support for a debug mode */
/* #undef _EVENT_DISABLE_DEBUG_MODE */
/* Define if libevent should not allow replacing the mm functions */
/* #undef _EVENT_DISABLE_MM_REPLACEMENT */
/* Define if libevent should not be compiled with thread support */
/* #undef _EVENT_DISABLE_THREAD_SUPPORT */
/* Define to 1 if you have the `arc4random' function. */
#define _EVENT_HAVE_ARC4RANDOM 1
/* Define to 1 if you have the `arc4random_buf' function. */
#define _EVENT_HAVE_ARC4RANDOM_BUF 1
/* Define to 1 if you have the <arpa/inet.h> header file. */
#define _EVENT_HAVE_ARPA_INET_H 1
/* Define to 1 if you have the `clock_gettime' function. */
#define _EVENT_HAVE_CLOCK_GETTIME 1
/* Define to 1 if you have the declaration of `CTL_KERN', and to 0 if you
don't. */
#define _EVENT_HAVE_DECL_CTL_KERN 1
/* Define to 1 if you have the declaration of `KERN_ARND', and to 0 if you
don't. */
#define _EVENT_HAVE_DECL_KERN_ARND 1
/* Define to 1 if you have the declaration of `KERN_RANDOM', and to 0 if you
don't. */
#define _EVENT_HAVE_DECL_KERN_RANDOM 0
/* Define to 1 if you have the declaration of `RANDOM_UUID', and to 0 if you
don't. */
#define _EVENT_HAVE_DECL_RANDOM_UUID 0
/* Define if /dev/poll is available */
/* #undef _EVENT_HAVE_DEVPOLL */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define _EVENT_HAVE_DLFCN_H 1
/* Define if your system supports the epoll system calls */
/* #undef _EVENT_HAVE_EPOLL */
/* Define to 1 if you have the `epoll_ctl' function. */
/* #undef _EVENT_HAVE_EPOLL_CTL */
/* Define to 1 if you have the `eventfd' function. */
/* #undef _EVENT_HAVE_EVENTFD */
/* Define if your system supports event ports */
/* #undef _EVENT_HAVE_EVENT_PORTS */
/* Define to 1 if you have the `fcntl' function. */
#define _EVENT_HAVE_FCNTL 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define _EVENT_HAVE_FCNTL_H 1
/* Define to 1 if the system has the type `fd_mask'. */
#define _EVENT_HAVE_FD_MASK 1
/* Do we have getaddrinfo()? */
#define _EVENT_HAVE_GETADDRINFO 1
/* Define to 1 if you have the `getegid' function. */
#define _EVENT_HAVE_GETEGID 1
/* Define to 1 if you have the `geteuid' function. */
#define _EVENT_HAVE_GETEUID 1
/* Define this if you have any gethostbyname_r() */
/* #undef _EVENT_HAVE_GETHOSTBYNAME_R */
/* Define this if gethostbyname_r takes 3 arguments */
/* #undef _EVENT_HAVE_GETHOSTBYNAME_R_3_ARG */
/* Define this if gethostbyname_r takes 5 arguments */
/* #undef _EVENT_HAVE_GETHOSTBYNAME_R_5_ARG */
/* Define this if gethostbyname_r takes 6 arguments */
/* #undef _EVENT_HAVE_GETHOSTBYNAME_R_6_ARG */
/* Define to 1 if you have the `getnameinfo' function. */
#define _EVENT_HAVE_GETNAMEINFO 1
/* Define to 1 if you have the `getprotobynumber' function. */
#define _EVENT_HAVE_GETPROTOBYNUMBER 1
/* Define to 1 if you have the `getservbyname' function. */
/* #undef _EVENT_HAVE_GETSERVBYNAME */
/* Define to 1 if you have the `gettimeofday' function. */
#define _EVENT_HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the `inet_aton' function. */
#define _EVENT_HAVE_INET_ATON 1
/* Define to 1 if you have the `inet_ntop' function. */
#define _EVENT_HAVE_INET_NTOP 1
/* Define to 1 if you have the `inet_pton' function. */
#define _EVENT_HAVE_INET_PTON 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define _EVENT_HAVE_INTTYPES_H 1
/* Define to 1 if you have the `issetugid' function. */
#define _EVENT_HAVE_ISSETUGID 1
/* Define to 1 if you have the `kqueue' function. */
#define _EVENT_HAVE_KQUEUE 1
/* Define if the system has zlib */
#define _EVENT_HAVE_LIBZ 1
/* Define to 1 if you have the <memory.h> header file. */
#define _EVENT_HAVE_MEMORY_H 1
/* Define to 1 if you have the `mmap' function. */
#define _EVENT_HAVE_MMAP 1
/* Define to 1 if you have the <netdb.h> header file. */
#define _EVENT_HAVE_NETDB_H 1
/* Define to 1 if you have the <netinet/in6.h> header file. */
/* #undef _EVENT_HAVE_NETINET_IN6_H */
/* Define to 1 if you have the <netinet/in.h> header file. */
#define _EVENT_HAVE_NETINET_IN_H 1
/* Define if the system has openssl */
#define _EVENT_HAVE_OPENSSL 1
/* Define to 1 if you have the <openssl/bio.h> header file. */
#define _EVENT_HAVE_OPENSSL_BIO_H 1
/* Define to 1 if you have the `pipe' function. */
#define _EVENT_HAVE_PIPE 1
/* Define to 1 if you have the `poll' function. */
#define _EVENT_HAVE_POLL 1
/* Define to 1 if you have the <poll.h> header file. */
#define _EVENT_HAVE_POLL_H 1
/* Define to 1 if you have the `port_create' function. */
/* #undef _EVENT_HAVE_PORT_CREATE */
/* Define to 1 if you have the <port.h> header file. */
/* #undef _EVENT_HAVE_PORT_H */
/* Define if you have POSIX threads libraries and header files. */
/* #undef _EVENT_HAVE_PTHREAD */
/* Define if we have pthreads on this system */
#define _EVENT_HAVE_PTHREADS 1
/* Define to 1 if you have the `putenv' function. */
#define _EVENT_HAVE_PUTENV 1
/* Define to 1 if the system has the type `sa_family_t'. */
#define _EVENT_HAVE_SA_FAMILY_T 1
/* Define to 1 if you have the `select' function. */
#define _EVENT_HAVE_SELECT 1
/* Define to 1 if you have the `sendfile' function. */
/* #undef _EVENT_HAVE_SENDFILE */
/* Define to 1 if you have the `setenv' function. */
#define _EVENT_HAVE_SETENV 1
/* Define if F_SETFD is defined in <fcntl.h> */
#define _EVENT_HAVE_SETFD 1
/* Define to 1 if you have the `sigaction' function. */
#define _EVENT_HAVE_SIGACTION 1
/* Define to 1 if you have the `signal' function. */
#define _EVENT_HAVE_SIGNAL 1
/* Define to 1 if you have the `splice' function. */
/* #undef _EVENT_HAVE_SPLICE */
/* Define to 1 if you have the <stdarg.h> header file. */
#define _EVENT_HAVE_STDARG_H 1
/* Define to 1 if you have the <stddef.h> header file. */
#define _EVENT_HAVE_STDDEF_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define _EVENT_HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define _EVENT_HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define _EVENT_HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define _EVENT_HAVE_STRING_H 1
/* Define to 1 if you have the `strlcpy' function. */
#define _EVENT_HAVE_STRLCPY 1
/* Define to 1 if you have the `strsep' function. */
#define _EVENT_HAVE_STRSEP 1
/* Define to 1 if you have the `strtok_r' function. */
#define _EVENT_HAVE_STRTOK_R 1
/* Define to 1 if you have the `strtoll' function. */
#define _EVENT_HAVE_STRTOLL 1
/* Define to 1 if the system has the type `struct addrinfo'. */
#define _EVENT_HAVE_STRUCT_ADDRINFO 1
/* Define to 1 if the system has the type `struct in6_addr'. */
#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
/* Define to 1 if `s6_addr16' is a member of `struct in6_addr'. */
/* #undef _EVENT_HAVE_STRUCT_IN6_ADDR_S6_ADDR16 */
/* Define to 1 if `s6_addr32' is a member of `struct in6_addr'. */
/* #undef _EVENT_HAVE_STRUCT_IN6_ADDR_S6_ADDR32 */
/* Define to 1 if the system has the type `struct sockaddr_in6'. */
#define _EVENT_HAVE_STRUCT_SOCKADDR_IN6 1
/* Define to 1 if `sin6_len' is a member of `struct sockaddr_in6'. */
#define _EVENT_HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN 1
/* Define to 1 if `sin_len' is a member of `struct sockaddr_in'. */
#define _EVENT_HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 1
/* Define to 1 if the system has the type `struct sockaddr_storage'. */
#define _EVENT_HAVE_STRUCT_SOCKADDR_STORAGE 1
/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
#define _EVENT_HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
/* #undef _EVENT_HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */
/* Define to 1 if you have the `sysctl' function. */
#define _EVENT_HAVE_SYSCTL 1
/* Define to 1 if you have the <sys/devpoll.h> header file. */
/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
/* Define to 1 if you have the <sys/epoll.h> header file. */
/* #undef _EVENT_HAVE_SYS_EPOLL_H */
/* Define to 1 if you have the <sys/eventfd.h> header file. */
/* #undef _EVENT_HAVE_SYS_EVENTFD_H */
/* Define to 1 if you have the <sys/event.h> header file. */
#define _EVENT_HAVE_SYS_EVENT_H 1
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define _EVENT_HAVE_SYS_IOCTL_H 1
/* Define to 1 if you have the <sys/mman.h> header file. */
#define _EVENT_HAVE_SYS_MMAN_H 1
/* Define to 1 if you have the <sys/param.h> header file. */
#define _EVENT_HAVE_SYS_PARAM_H 1
/* Define to 1 if you have the <sys/queue.h> header file. */
#define _EVENT_HAVE_SYS_QUEUE_H 1
/* Define to 1 if you have the <sys/select.h> header file. */
#define _EVENT_HAVE_SYS_SELECT_H 1
/* Define to 1 if you have the <sys/sendfile.h> header file. */
/* #undef _EVENT_HAVE_SYS_SENDFILE_H */
/* Define to 1 if you have the <sys/socket.h> header file. */
#define _EVENT_HAVE_SYS_SOCKET_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define _EVENT_HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/sysctl.h> header file. */
#define _EVENT_HAVE_SYS_SYSCTL_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define _EVENT_HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define _EVENT_HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/uio.h> header file. */
#define _EVENT_HAVE_SYS_UIO_H 1
/* Define to 1 if you have the <sys/wait.h> header file. */
#define _EVENT_HAVE_SYS_WAIT_H 1
/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
#define _EVENT_HAVE_TAILQFOREACH 1
/* Define if timeradd is defined in <sys/time.h> */
#define _EVENT_HAVE_TIMERADD 1
/* Define if timerclear is defined in <sys/time.h> */
#define _EVENT_HAVE_TIMERCLEAR 1
/* Define if timercmp is defined in <sys/time.h> */
#define _EVENT_HAVE_TIMERCMP 1
/* Define if timerisset is defined in <sys/time.h> */
#define _EVENT_HAVE_TIMERISSET 1
/* Define to 1 if the system has the type `uint16_t'. */
#define _EVENT_HAVE_UINT16_T 1
/* Define to 1 if the system has the type `uint32_t'. */
#define _EVENT_HAVE_UINT32_T 1
/* Define to 1 if the system has the type `uint64_t'. */
#define _EVENT_HAVE_UINT64_T 1
/* Define to 1 if the system has the type `uint8_t'. */
#define _EVENT_HAVE_UINT8_T 1
/* Define to 1 if the system has the type `uintptr_t'. */
#define _EVENT_HAVE_UINTPTR_T 1
/* Define to 1 if you have the `umask' function. */
#define _EVENT_HAVE_UMASK 1
/* Define to 1 if you have the <unistd.h> header file. */
#define _EVENT_HAVE_UNISTD_H 1
/* Define to 1 if you have the `unsetenv' function. */
#define _EVENT_HAVE_UNSETENV 1
/* Define to 1 if you have the `vasprintf' function. */
#define _EVENT_HAVE_VASPRINTF 1
/* Define if kqueue works correctly with pipes */
#define _EVENT_HAVE_WORKING_KQUEUE 1
/* Define to 1 if you have the <zlib.h> header file. */
#define _EVENT_HAVE_ZLIB_H 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define _EVENT_LT_OBJDIR ".libs/"
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
/* #undef _EVENT_NO_MINUS_C_MINUS_O */
/* Numeric representation of the version */
#define _EVENT_NUMERIC_VERSION 0x02001500
/* Name of package */
#define _EVENT_PACKAGE "libevent"
/* Define to the address where bug reports for this package should be sent. */
#define _EVENT_PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define _EVENT_PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define _EVENT_PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define _EVENT_PACKAGE_TARNAME ""
/* Define to the home page for this package. */
#define _EVENT_PACKAGE_URL ""
/* Define to the version of this package. */
#define _EVENT_PACKAGE_VERSION ""
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
/* #undef _EVENT_PTHREAD_CREATE_JOINABLE */
/* The size of `int', as computed by sizeof. */
#define _EVENT_SIZEOF_INT 4
/* The size of `long', as computed by sizeof. */
#define _EVENT_SIZEOF_LONG 8
/* The size of `long long', as computed by sizeof. */
#define _EVENT_SIZEOF_LONG_LONG 8
/* The size of `pthread_t', as computed by sizeof. */
#define _EVENT_SIZEOF_PTHREAD_T 8
/* The size of `short', as computed by sizeof. */
#define _EVENT_SIZEOF_SHORT 2
/* The size of `size_t', as computed by sizeof. */
#define _EVENT_SIZEOF_SIZE_T 8
/* The size of `void *', as computed by sizeof. */
#define _EVENT_SIZEOF_VOID_P 8
/* Define to 1 if you have the ANSI C header files. */
#define _EVENT_STDC_HEADERS 1
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#define _EVENT_TIME_WITH_SYS_TIME 1
/* Version number of package */
#define _EVENT_VERSION "2.0.21-stable"
/* Define to appropriate substitue if compiler doesnt have __func__ */
/* #undef _EVENT___func__ */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef _EVENT_const */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef _EVENT___cplusplus
/* #undef _EVENT_inline */
#endif
/* Define to `int' if <sys/types.h> does not define. */
/* #undef _EVENT_pid_t */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef _EVENT_size_t */
/* Define to unsigned int if you dont have it */
/* #undef _EVENT_socklen_t */
/* Define to `int' if <sys/types.h> does not define. */
/* #undef _EVENT_ssize_t */
#endif /* event2/event-config.h */

View File

@ -4653,9 +4653,15 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
actorvar = md.actorDecl().var()
type = md.decl.type.constructedType()
failif = StmtIf(cond)
failif.addifstmts(self.destroyActor(md, actorvar,
why=_DestroyReason.FailedConstructor)
+ [ StmtReturn(ExprLiteral.NULL) ])
if self.side=='child':
# in the child process this should not fail
failif.addifstmt(_runtimeAbort('constructor for actor failed'))
else:
failif.addifstmts(self.destroyActor(md, actorvar,
why=_DestroyReason.FailedConstructor))
failif.addifstmt(StmtReturn(ExprLiteral.NULL))
return [ failif ]
def genHelperCtor(self, md):

View File

@ -244,7 +244,6 @@ CPPSRCS += MIR.cpp \
Snapshots.cpp \
Safepoints.cpp \
StupidAllocator.cpp \
TypeOracle.cpp \
TypePolicy.cpp \
ValueNumbering.cpp \
RangeAnalysis.cpp \

View File

@ -1247,8 +1247,8 @@ function ParallelArrayToString() {
* sequential execution
*/
function AssertSequentialIsOK(mode) {
if (mode && mode.mode !== "seq" && ParallelTestsShouldPass())
ThrowError(JSMSG_WRONG_VALUE, "par", "seq");
if (mode && mode.mode && mode.mode !== "seq" && ParallelTestsShouldPass())
ThrowError(JSMSG_WRONG_VALUE, "parallel execution", "sequential was forced");
}
/**

View File

@ -1073,6 +1073,8 @@ conic/conicstatisticsevent.h
#endif
#if MOZ_NATIVE_LIBEVENT==1
event.h
#else
sys/event.h
#endif
#ifdef MOZ_ENABLE_LIBPROXY
proxy.h

View File

@ -57,3 +57,90 @@ BaselineInspector::maybeMonomorphicShapeForPropertyOp(jsbytecode *pc)
return NULL;
}
ICStub::Kind
BaselineInspector::monomorphicStubKind(jsbytecode *pc)
{
if (!hasBaselineScript())
return ICStub::INVALID;
const ICEntry &entry = icEntryFromPC(pc);
ICStub *stub = entry.firstStub();
ICStub *next = stub->next();
if (!next || !next->isFallback())
return ICStub::INVALID;
return stub->kind();
}
bool
BaselineInspector::dimorphicStubKind(jsbytecode *pc, ICStub::Kind *pfirst, ICStub::Kind *psecond)
{
if (!hasBaselineScript())
return false;
const ICEntry &entry = icEntryFromPC(pc);
ICStub *stub = entry.firstStub();
ICStub *next = stub->next();
ICStub *after = next ? next->next() : NULL;
if (!after || !after->isFallback())
return false;
*pfirst = stub->kind();
*psecond = next->kind();
return true;
}
MIRType
BaselineInspector::expectedResultType(jsbytecode *pc)
{
// Look at the IC entries for this op to guess what type it will produce,
// returning MIRType_None otherwise.
ICStub::Kind kind = monomorphicStubKind(pc);
switch (kind) {
case ICStub::BinaryArith_Int32:
case ICStub::BinaryArith_BooleanWithInt32:
case ICStub::UnaryArith_Int32:
return MIRType_Int32;
case ICStub::BinaryArith_Double:
case ICStub::BinaryArith_DoubleWithInt32:
case ICStub::UnaryArith_Double:
return MIRType_Double;
case ICStub::BinaryArith_StringConcat:
case ICStub::BinaryArith_StringObjectConcat:
return MIRType_String;
default:
return MIRType_None;
}
}
// Whether a baseline stub kind is suitable for a double comparison that
// converts its operands to doubles.
static bool
CanUseDoubleCompare(ICStub::Kind kind)
{
return kind == ICStub::Compare_Double || kind == ICStub::Compare_NumberWithUndefined;
}
MCompare::CompareType
BaselineInspector::expectedCompareType(jsbytecode *pc)
{
ICStub::Kind kind = monomorphicStubKind(pc);
if (CanUseDoubleCompare(kind))
return MCompare::Compare_Double;
ICStub::Kind first, second;
if (dimorphicStubKind(pc, &first, &second)) {
if (CanUseDoubleCompare(first) && CanUseDoubleCompare(second))
return MCompare::Compare_Double;
}
return MCompare::Compare_Unknown;
}

View File

@ -12,6 +12,7 @@
#include "BaselineJIT.h"
#include "BaselineIC.h"
#include "MIR.h"
namespace js {
namespace ion {
@ -88,12 +89,18 @@ class BaselineInspector
return ICInspectorType(this, pc, ent);
}
ICStub::Kind monomorphicStubKind(jsbytecode *pc);
bool dimorphicStubKind(jsbytecode *pc, ICStub::Kind *pfirst, ICStub::Kind *psecond);
public:
RawShape maybeMonomorphicShapeForPropertyOp(jsbytecode *pc);
SetElemICInspector setElemICInspector(jsbytecode *pc) {
return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
}
MIRType expectedResultType(jsbytecode *pc);
MCompare::CompareType expectedCompareType(jsbytecode *pc);
};
} // namespace ion

View File

@ -990,7 +990,7 @@ CodeGenerator::visitTypeBarrier(LTypeBarrier *lir)
Register scratch = ToRegister(lir->temp());
Label matched, miss;
masm.guardTypeSet(operand, lir->mir()->typeSet(), scratch, &matched, &miss);
masm.guardTypeSet(operand, lir->mir()->resultTypeSet(), scratch, &matched, &miss);
masm.jump(&miss);
if (!bailoutFrom(&miss, lir->snapshot()))
return false;
@ -1815,7 +1815,7 @@ CodeGenerator::generateArgumentsChecks()
for (uint32_t i = START_SLOT; i < CountArgSlots(info.fun()); i++) {
// All initial parameters are guaranteed to be MParameters.
MParameter *param = rp->getOperand(i)->toParameter();
const types::TypeSet *types = param->typeSet();
const types::TypeSet *types = param->resultTypeSet();
if (!types || types->unknown())
continue;
@ -4752,6 +4752,19 @@ CodeGenerator::visitCallSetElement(LCallSetElement *lir)
return callVM(SetObjectElementInfo, lir);
}
typedef bool (*InitElementArrayFn)(JSContext *, jsbytecode *, HandleObject, uint32_t, HandleValue);
static const VMFunction InitElementArrayInfo = FunctionInfo<InitElementArrayFn>(js::InitElementArray);
bool
CodeGenerator::visitCallInitElementArray(LCallInitElementArray *lir)
{
pushArg(ToValue(lir, LCallInitElementArray::Value));
pushArg(Imm32(lir->mir()->index()));
pushArg(ToRegister(lir->getOperand(0)));
pushArg(ImmWord(lir->mir()->resumePoint()->pc()));
return callVM(InitElementArrayInfo, lir);
}
bool
CodeGenerator::visitLoadFixedSlotV(LLoadFixedSlotV *ins)
{

View File

@ -165,6 +165,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitCallGetProperty(LCallGetProperty *lir);
bool visitCallGetElement(LCallGetElement *lir);
bool visitCallSetElement(LCallSetElement *lir);
bool visitCallInitElementArray(LCallInitElementArray *lir);
bool visitThrow(LThrow *lir);
bool visitTypeOfV(LTypeOfV *lir);
bool visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool);

View File

@ -1287,7 +1287,8 @@ static const size_t BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
template <typename CompileContext>
static AbortReason
IonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing,
IonCompile(JSContext *cx, JSScript *script,
AbstractFramePtr fp, jsbytecode *osrPc, bool constructing,
CompileContext &compileContext)
{
#if JS_TRACE_LOGGING
@ -1297,6 +1298,9 @@ IonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osrPc,
script);
#endif
if (!script->ensureRanAnalysis(cx))
return AbortReason_Alloc;
LifoAlloc *alloc = cx->new_<LifoAlloc>(BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
if (!alloc)
return AbortReason_Alloc;
@ -1316,15 +1320,11 @@ IonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osrPc,
MIRGraph *graph = alloc->new_<MIRGraph>(temp);
ExecutionMode executionMode = compileContext.executionMode();
CompileInfo *info = alloc->new_<CompileInfo>(script, fun, osrPc, constructing,
CompileInfo *info = alloc->new_<CompileInfo>(script, script->function(), osrPc, constructing,
executionMode);
if (!info)
return AbortReason_Alloc;
TypeInferenceOracle oracle;
if (!oracle.init(cx, script, /* inlinedCall = */ false))
return AbortReason_Disable;
BaselineInspector inspector(cx, script);
AutoFlushCache afc("IonCompile");
@ -1335,7 +1335,7 @@ IonCompile(JSContext *cx, JSScript *script, JSFunction *fun, jsbytecode *osrPc,
AutoTempAllocatorRooter root(cx, temp);
IonBuilder *builder = alloc->new_<IonBuilder>(cx, temp, graph, &oracle, &inspector, info);
IonBuilder *builder = alloc->new_<IonBuilder>(cx, temp, graph, &inspector, info, fp);
if (!builder)
return AbortReason_Alloc;
@ -1519,7 +1519,8 @@ CanIonCompileScript(JSContext *cx, HandleScript script)
template <typename CompileContext>
static MethodStatus
Compile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrPc, bool constructing,
Compile(JSContext *cx, HandleScript script,
AbstractFramePtr fp, jsbytecode *osrPc, bool constructing,
CompileContext &compileContext)
{
JS_ASSERT(ion::IsEnabled(cx));
@ -1570,7 +1571,7 @@ Compile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrP
}
}
AbortReason reason = IonCompile(cx, script, fun, osrPc, constructing, compileContext);
AbortReason reason = IonCompile(cx, script, fp, osrPc, constructing, compileContext);
if (reason == AbortReason_Disable)
return Method_CantCompile;
@ -1613,10 +1614,9 @@ ion::CanEnterAtBranch(JSContext *cx, JSScript *script, AbstractFramePtr fp,
}
// Attempt compilation. Returns Method_Compiled if already compiled.
RootedFunction fun(cx, fp.isFunctionFrame() ? fp.fun() : NULL);
SequentialCompileContext compileContext;
RootedScript rscript(cx, script);
MethodStatus status = Compile(cx, rscript, fun, pc, isConstructing, compileContext);
MethodStatus status = Compile(cx, rscript, fp, pc, isConstructing, compileContext);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
@ -1677,10 +1677,9 @@ ion::CanEnter(JSContext *cx, JSScript *script, AbstractFramePtr fp, bool isConst
}
// Attempt compilation. Returns Method_Compiled if already compiled.
RootedFunction fun(cx, fp.isFunctionFrame() ? fp.fun() : NULL);
SequentialCompileContext compileContext;
RootedScript rscript(cx, script);
MethodStatus status = Compile(cx, rscript, fun, NULL, isConstructing, compileContext);
MethodStatus status = Compile(cx, rscript, fp, NULL, isConstructing, compileContext);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
@ -1708,8 +1707,7 @@ ion::CompileFunctionForBaseline(JSContext *cx, HandleScript script, AbstractFram
// Attempt compilation. Returns Method_Compiled if already compiled.
SequentialCompileContext compileContext;
RootedFunction fun(cx, fp.fun());
MethodStatus status = Compile(cx, script, fun, NULL, isConstructing, compileContext);
MethodStatus status = Compile(cx, script, fp, NULL, isConstructing, compileContext);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
@ -1800,7 +1798,7 @@ ParallelCompileContext::compileTransitively()
}
// Attempt compilation. Returns Method_Compiled if already compiled.
MethodStatus status = Compile(cx_, script, fun, NULL, false, *this);
MethodStatus status = Compile(cx_, script, AbstractFramePtr(), NULL, false, *this);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx_, script, ParallelExecution);

View File

@ -528,7 +528,7 @@ TypeAnalyzer::adjustPhiInputs(MPhi *phi)
if (in->type() == MIRType_Value)
continue;
if (in->isUnbox()) {
if (in->isUnbox() && phi->typeIncludes(in->toUnbox()->input())) {
// The input is being explicitly unboxed, so sneak past and grab
// the original box.
phi->replaceOperand(i, in->toUnbox()->input());
@ -1271,8 +1271,8 @@ TryEliminateTypeBarrier(MTypeBarrier *barrier, bool *eliminated)
{
JS_ASSERT(!*eliminated);
const types::StackTypeSet *barrierTypes = barrier->typeSet();
const types::StackTypeSet *inputTypes = barrier->input()->typeSet();
const types::StackTypeSet *barrierTypes = barrier->resultTypeSet();
const types::StackTypeSet *inputTypes = barrier->input()->resultTypeSet();
if (!barrierTypes || !inputTypes)
return true;

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@ class IonBuilder : public MIRGenerator
{
enum ControlStatus {
ControlStatus_Error,
ControlStatus_Abort,
ControlStatus_Ended, // There is no continuation/join point.
ControlStatus_Joined, // Created a join node.
ControlStatus_Jumped, // Parsing another branch at the same level.
@ -91,6 +92,9 @@ class IonBuilder : public MIRGenerator
// Common entry point.
MBasicBlock *entry;
// Whether OSR is being performed for this loop.
bool osr;
// Position of where the loop body starts and ends.
jsbytecode *bodyStart;
jsbytecode *bodyEnd;
@ -98,6 +102,9 @@ class IonBuilder : public MIRGenerator
// pc immediately after the loop exits.
jsbytecode *exitpc;
// pc for 'continue' jumps.
jsbytecode *continuepc;
// Common exit point. Created lazily, so it may be NULL.
MBasicBlock *successor;
@ -105,6 +112,12 @@ class IonBuilder : public MIRGenerator
DeferredEdge *breaks;
DeferredEdge *continues;
// Initial state, in case loop processing is restarted.
State initialState;
jsbytecode *initialPc;
jsbytecode *initialStopAt;
jsbytecode *loopHead;
// For-loops only.
jsbytecode *condpc;
jsbytecode *updatepc;
@ -173,7 +186,7 @@ class IonBuilder : public MIRGenerator
public:
IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
TypeOracle *oracle, BaselineInspector *inspector, CompileInfo *info,
BaselineInspector *inspector, CompileInfo *info, AbstractFramePtr fp,
size_t inliningDepth = 0, uint32_t loopDepth = 0);
bool build();
@ -200,6 +213,7 @@ class IonBuilder : public MIRGenerator
bool canInlineTarget(JSFunction *target, CallInfo &callInfo);
void popCfgStack();
DeferredEdge *filterDeadDeferredEdges(DeferredEdge *edge);
bool processDeferredContinues(CFGState &state);
ControlStatus processControlEnd();
ControlStatus processCfgStack();
@ -226,9 +240,11 @@ class IonBuilder : public MIRGenerator
ControlStatus processContinue(JSOp op);
ControlStatus processBreak(JSOp op, jssrcnote *sn);
ControlStatus maybeLoop(JSOp op, jssrcnote *sn);
bool pushLoop(CFGState::State state, jsbytecode *stopAt, MBasicBlock *entry,
bool pushLoop(CFGState::State state, jsbytecode *stopAt, MBasicBlock *entry, bool osr,
jsbytecode *loopHead, jsbytecode *initialPc,
jsbytecode *bodyStart, jsbytecode *bodyEnd, jsbytecode *exitpc,
jsbytecode *continuepc = NULL);
void analyzeNewLoopTypes(MBasicBlock *entry, jsbytecode *start, jsbytecode *end);
MBasicBlock *addBlock(MBasicBlock *block, uint32_t loopDepth);
MBasicBlock *newBlock(MBasicBlock *predecessor, jsbytecode *pc);
@ -237,7 +253,7 @@ class IonBuilder : public MIRGenerator
MBasicBlock *newBlockPopN(MBasicBlock *predecessor, jsbytecode *pc, uint32_t popped);
MBasicBlock *newBlockAfter(MBasicBlock *at, MBasicBlock *predecessor, jsbytecode *pc);
MBasicBlock *newOsrPreheader(MBasicBlock *header, jsbytecode *loopEntry);
MBasicBlock *newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc);
MBasicBlock *newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool osr);
MBasicBlock *newBlock(jsbytecode *pc) {
return newBlock(NULL, pc);
}
@ -257,6 +273,16 @@ class IonBuilder : public MIRGenerator
// handles any pending breaks.
ControlStatus finishLoop(CFGState &state, MBasicBlock *successor);
// Incorporates a type/typeSet into an OSR value for a loop, after the loop
// body has been processed.
bool addOsrValueTypeBarrier(uint32_t slot, MInstruction **def,
MIRType type, types::StackTypeSet *typeSet);
bool maybeAddOsrTypeBarriers();
// Restarts processing of a loop if the type information at its header was
// incomplete.
ControlStatus restartLoop(CFGState state);
void assertValidLoopHeadOp(jsbytecode *pc);
ControlStatus forLoop(JSOp op, jssrcnote *sn);
@ -278,16 +304,8 @@ class IonBuilder : public MIRGenerator
bool pushConstant(const Value &v);
// Add a guard which ensure that the set of type which goes through this
// generated code correspond to the observed or infered (actual) type.
bool pushTypeBarrier(MInstruction *ins, types::StackTypeSet *actual, types::StackTypeSet *observed);
// Add a guard which ensure that the set of type does not go through. Some
// instructions, such as function calls, can have an excluded set of types
// which would be added after invalidation if they are observed in the
// callee.
void addTypeBarrier(uint32_t i, CallInfo &callinfo, types::StackTypeSet *calleeObs);
void monitorResult(MInstruction *ins, types::TypeSet *barrier, types::StackTypeSet *types);
// generated code correspond to the observed types for the bytecode.
bool pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bool needBarrier);
JSObject *getSingletonPrototype(JSFunction *target);
@ -307,23 +325,21 @@ class IonBuilder : public MIRGenerator
bool invalidatedIdempotentCache();
bool loadSlot(MDefinition *obj, HandleShape shape, MIRType rvalType);
bool loadSlot(MDefinition *obj, HandleShape shape, MIRType rvalType,
bool barrier, types::StackTypeSet *types);
bool storeSlot(MDefinition *obj, RawShape shape, MDefinition *value, bool needsBarrier);
// jsop_getprop() helpers.
bool getPropTryArgumentsLength(bool *emitted);
bool getPropTryConstant(bool *emitted, HandleId id, types::StackTypeSet *barrier,
types::StackTypeSet *types, TypeOracle::UnaryTypes unaryTypes);
bool getPropTryConstant(bool *emitted, HandleId id, types::StackTypeSet *types);
bool getPropTryDefiniteSlot(bool *emitted, HandlePropertyName name,
types::StackTypeSet *barrier, types::StackTypeSet *types,
TypeOracle::Unary unary, TypeOracle::UnaryTypes unaryTypes);
bool getPropTryCommonGetter(bool *emitted, HandleId id, types::StackTypeSet *barrier,
types::StackTypeSet *types, TypeOracle::UnaryTypes unaryTypes);
bool getPropTryMonomorphic(bool *emitted, HandleId id, types::StackTypeSet *barrier,
TypeOracle::Unary unary, TypeOracle::UnaryTypes unaryTypes);
bool barrier, types::StackTypeSet *types);
bool getPropTryCommonGetter(bool *emitted, HandleId id,
bool barrier, types::StackTypeSet *types);
bool getPropTryMonomorphic(bool *emitted, HandleId id,
bool barrier, types::StackTypeSet *types);
bool getPropTryPolymorphic(bool *emitted, HandlePropertyName name, HandleId id,
types::StackTypeSet *barrier, types::StackTypeSet *types,
TypeOracle::Unary unary, TypeOracle::UnaryTypes unaryTypes);
bool barrier, types::StackTypeSet *types);
// Typed array helpers.
MInstruction *getTypedArrayLength(MDefinition *obj);
@ -361,7 +377,7 @@ class IonBuilder : public MIRGenerator
bool jsop_getelem_typed(int arrayType);
bool jsop_getelem_string();
bool jsop_setelem();
bool jsop_setelem_dense();
bool jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion);
bool jsop_setelem_typed(int arrayType);
bool jsop_length();
bool jsop_length_fastPath();
@ -404,16 +420,13 @@ class IonBuilder : public MIRGenerator
};
// Oracles.
bool canEnterInlinedFunction(JSFunction *target);
bool makeInliningDecision(JSFunction *target, CallInfo &callInfo);
uint32_t selectInliningTargets(AutoObjectVector &targets, CallInfo &callInfo, Vector<bool> &choiceSet);
// Native inlining helpers.
types::StackTypeSet *getInlineReturnTypeSet();
MIRType getInlineReturnType();
types::StackTypeSet *getInlineThisTypeSet(CallInfo &callInfo);
MIRType getInlineThisType(CallInfo &callInfo);
types::StackTypeSet *getInlineArgTypeSet(CallInfo &callInfo, uint32_t arg);
MIRType getInlineArgType(CallInfo &callInfo, uint32_t arg);
// Array natives.
InliningStatus inlineArray(CallInfo &callInfo);
@ -482,12 +495,8 @@ class IonBuilder : public MIRGenerator
bool anyFunctionIsCloneAtCallsite(types::StackTypeSet *funTypes);
MDefinition *makeCallsiteClone(HandleFunction target, MDefinition *fun);
MCall *makeCallHelper(HandleFunction target, CallInfo &callInfo,
types::StackTypeSet *calleeTypes, bool cloneAtCallsite);
bool makeCallBarrier(HandleFunction target, CallInfo &callInfo,
types::StackTypeSet *calleeTypes, bool cloneAtCallsite);
bool makeCall(HandleFunction target, CallInfo &callInfo,
types::StackTypeSet *calleeTypes, bool cloneAtCallsite);
MCall *makeCallHelper(HandleFunction target, CallInfo &callInfo, bool cloneAtCallsite);
bool makeCall(HandleFunction target, CallInfo &callInfo, bool cloneAtCallsite);
MDefinition *patchInlinedReturn(CallInfo &callInfo, MBasicBlock *exit, MBasicBlock *bottom);
MDefinition *patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasicBlock *bottom);
@ -507,7 +516,21 @@ class IonBuilder : public MIRGenerator
MGetPropertyCache *getPropCache, MBasicBlock *bottom,
Vector<MDefinition *, 8, IonAllocPolicy> &retvalDefns);
const types::StackTypeSet *cloneTypeSet(const types::StackTypeSet *types);
types::StackTypeSet *cloneTypeSet(types::StackTypeSet *types);
// Use one of the below methods for updating the current block, rather than
// updating |current| directly. setCurrent() should only be used in cases
// where the block cannot have phis whose type needs to be computed.
void setCurrentAndSpecializePhis(MBasicBlock *block) {
if (block)
block->specializePhis();
setCurrent(block);
}
void setCurrent(MBasicBlock *block) {
current = block;
}
// A builder is inextricably tied to a particular script.
HeapPtrScript script_;
@ -533,6 +556,7 @@ class IonBuilder : public MIRGenerator
private:
JSContext *cx;
AbstractFramePtr fp;
AbortReason abortReason_;
jsbytecode *pc;
@ -551,12 +575,15 @@ class IonBuilder : public MIRGenerator
Vector<ControlFlowInfo, 0, IonAllocPolicy> switches_;
Vector<ControlFlowInfo, 2, IonAllocPolicy> labels_;
Vector<MInstruction *, 2, IonAllocPolicy> iterators_;
TypeOracle *oracle;
BaselineInspector *inspector;
size_t inliningDepth_;
Vector<MDefinition *, 0, IonAllocPolicy> inlinedArguments_;
Vector<types::StackTypeSet *, 0, IonAllocPolicy> inlinedArgumentTypes_;
// Cutoff to disable compilation if excessive time is spent reanalyzing
// loop bodies to compute a fixpoint of the types for loop variables.
static const size_t MAX_LOOP_RESTARTS = 20;
size_t numLoopRestarts_;
// True if script->failedBoundsCheck is set for the current script or
// an outer script.
@ -566,6 +593,9 @@ class IonBuilder : public MIRGenerator
// an outer script.
bool failedShapeGuard_;
// Has an iterator other than 'for in'.
bool nonStringIteration_;
// If this script can use a lazy arguments object, it will be pre-created
// here.
MInstruction *lazyArguments_;
@ -573,13 +603,6 @@ class IonBuilder : public MIRGenerator
class CallInfo
{
types::StackTypeSet *barrier_;
types::StackTypeSet *types_;
types::TypeBarrier *argsBarriers_;
types::StackTypeSet *thisType_;
Vector<types::StackTypeSet *> argsType_;
MDefinition *fun_;
MDefinition *thisArg_;
Vector<MDefinition *> args_;
@ -588,25 +611,7 @@ class CallInfo
public:
CallInfo(JSContext *cx, bool constructing)
: barrier_(NULL),
types_(NULL),
argsBarriers_(NULL),
thisType_(NULL),
argsType_(cx),
fun_(NULL),
thisArg_(NULL),
args_(cx),
constructing_(constructing)
{ }
CallInfo(JSContext *cx, bool constructing,
types::StackTypeSet *types, types::StackTypeSet *barrier)
: barrier_(barrier),
types_(types),
argsBarriers_(NULL),
thisType_(NULL),
argsType_(cx),
fun_(NULL),
: fun_(NULL),
thisArg_(NULL),
args_(cx),
constructing_(constructing)
@ -615,21 +620,12 @@ class CallInfo
bool init(CallInfo &callInfo) {
JS_ASSERT(constructing_ == callInfo.constructing());
thisType_ = callInfo.thisType_;
if (thisType_ && !argsType_.append(callInfo.argsType_.begin(), callInfo.argsType_.end()))
return false;
fun_ = callInfo.fun();
thisArg_ = callInfo.thisArg();
if (!args_.append(callInfo.argv().begin(), callInfo.argv().end()))
return false;
if (callInfo.hasTypeInfo())
setTypeInfo(callInfo.types(), callInfo.barrier());
argsBarriers_ = callInfo.argsBarriers_;
return true;
}
@ -650,32 +646,6 @@ class CallInfo
return true;
}
bool initCallType(TypeOracle *oracle, HandleScript script, jsbytecode *pc) {
argsBarriers_ = oracle->callArgsBarrier(script, pc);
thisType_ = oracle->getCallArg(script, argc(), 0, pc);
if (!argsType_.reserve(argc()))
return false;
for (uint32_t i = 1; i <= argc(); i++)
argsType_.infallibleAppend(oracle->getCallArg(script, argc(), i, pc));
return true;
}
bool initFunApplyArguments(TypeOracle *oracle, HandleScript script, jsbytecode *pc,
Vector<types::StackTypeSet *> *types) {
argsBarriers_ = oracle->callArgsBarrier(script, pc);
thisType_ = oracle->getCallArg(script, 2, 1, pc);
if (!argsType_.append(types->begin(), types->end()))
return false;
return true;
}
bool hasCallType() {
// argsBarriers can be NULL is the caller does not need to guard its
// arguments again some value type expected by callees. On the other
// hand we would always have a thisType if the type info is initialized.
return hasTypeInfo() && thisType_;
}
void popFormals(MBasicBlock *current) {
current->popn(numFormals());
}
@ -688,16 +658,6 @@ class CallInfo
current->push(getArg(i));
}
void setTypeInfo(types::StackTypeSet *types, types::StackTypeSet *barrier) {
types_ = types;
barrier_ = barrier;
}
bool hasTypeInfo() const {
JS_ASSERT_IF(barrier_, types_);
return types_;
}
uint32_t argc() const {
return args_.length();
}
@ -714,20 +674,11 @@ class CallInfo
return args_;
}
Vector<types::StackTypeSet *> &argvType() {
return argsType_;
}
MDefinition *getArg(uint32_t i) {
JS_ASSERT(i < argc());
return args_[i];
}
types::StackTypeSet *getArgType(uint32_t i) {
JS_ASSERT(i < argc() && argc() == argsType_.length());
return argsType_[i];
}
void setArg(uint32_t i, MDefinition *def) {
JS_ASSERT(i < argc());
args_[i] = def;
@ -738,35 +689,14 @@ class CallInfo
return thisArg_;
}
types::StackTypeSet *thisType() {
JS_ASSERT(thisType_);
return thisType_;
}
void setThis(MDefinition *thisArg) {
thisArg_ = thisArg;
}
void setThisType(types::StackTypeSet *thisType) {
thisType_ = thisType;
}
bool constructing() {
return constructing_;
}
types::StackTypeSet *types() {
return types_;
}
types::StackTypeSet *barrier() {
return barrier_;
}
types::TypeBarrier *argsBarrier() {
return argsBarriers_;
}
void wrapArgs(MBasicBlock *current) {
thisArg_ = wrap(current, thisArg_);
for (uint32_t i = 0; i < argc(); i++)
@ -819,6 +749,8 @@ class CallInfo
}
};
bool TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *inputTypes);
} // namespace ion
} // namespace js

View File

@ -8,7 +8,6 @@
#define jsion_caches_h__
#include "IonCode.h"
#include "TypeOracle.h"
#include "Registers.h"
#include "vm/ForkJoin.h"

View File

@ -16,7 +16,6 @@
#endif
#include "ion/IonCompartment.h"
#include "ion/IonInstrumentation.h"
#include "ion/TypeOracle.h"
#include "ion/ParallelFunctions.h"
#include "vm/ForkJoin.h"

View File

@ -7,6 +7,7 @@
#ifndef jsion_types_h_
#define jsion_types_h_
#include "js/Value.h"
#include <jstypes.h>
namespace js {
@ -94,6 +95,114 @@ enum MIRType
MIRType_ForkJoinSlice // js::ForkJoinSlice*
};
static inline MIRType
MIRTypeFromValueType(JSValueType type)
{
switch (type) {
case JSVAL_TYPE_DOUBLE:
return MIRType_Double;
case JSVAL_TYPE_INT32:
return MIRType_Int32;
case JSVAL_TYPE_UNDEFINED:
return MIRType_Undefined;
case JSVAL_TYPE_STRING:
return MIRType_String;
case JSVAL_TYPE_BOOLEAN:
return MIRType_Boolean;
case JSVAL_TYPE_NULL:
return MIRType_Null;
case JSVAL_TYPE_OBJECT:
return MIRType_Object;
case JSVAL_TYPE_MAGIC:
return MIRType_Magic;
case JSVAL_TYPE_UNKNOWN:
return MIRType_Value;
default:
JS_NOT_REACHED("unexpected jsval type");
return MIRType_None;
}
}
static inline JSValueType
ValueTypeFromMIRType(MIRType type)
{
switch (type) {
case MIRType_Undefined:
return JSVAL_TYPE_UNDEFINED;
case MIRType_Null:
return JSVAL_TYPE_NULL;
case MIRType_Boolean:
return JSVAL_TYPE_BOOLEAN;
case MIRType_Int32:
return JSVAL_TYPE_INT32;
case MIRType_Double:
return JSVAL_TYPE_DOUBLE;
case MIRType_String:
return JSVAL_TYPE_STRING;
case MIRType_Magic:
return JSVAL_TYPE_MAGIC;
default:
JS_ASSERT(type == MIRType_Object);
return JSVAL_TYPE_OBJECT;
}
}
static inline JSValueTag
MIRTypeToTag(MIRType type)
{
return JSVAL_TYPE_TO_TAG(ValueTypeFromMIRType(type));
}
static inline const char *
StringFromMIRType(MIRType type)
{
switch (type) {
case MIRType_Undefined:
return "Undefined";
case MIRType_Null:
return "Null";
case MIRType_Boolean:
return "Bool";
case MIRType_Int32:
return "Int32";
case MIRType_Double:
return "Double";
case MIRType_String:
return "String";
case MIRType_Object:
return "Object";
case MIRType_Magic:
return "Magic";
case MIRType_Value:
return "Value";
case MIRType_None:
return "None";
case MIRType_Slots:
return "Slots";
case MIRType_Elements:
return "Elements";
case MIRType_Pointer:
return "Pointer";
case MIRType_ForkJoinSlice:
return "ForkJoinSlice";
default:
JS_NOT_REACHED("Unknown MIRType.");
return "";
}
}
static inline bool
IsNumberType(MIRType type)
{
return type == MIRType_Int32 || type == MIRType_Double;
}
static inline bool
IsNullOrUndefined(MIRType type)
{
return type == MIRType_Null || type == MIRType_Undefined;
}
#ifdef DEBUG
// Track the pipeline of opcodes which has produced a snapshot.
#define TRACK_SNAPSHOTS 1

View File

@ -8,7 +8,6 @@
#include "JSONSpewer.h"
#include "LIR.h"
#include "TypeOracle.h"
#include "MIR.h"
#include "MIRGraph.h"
#include "LinearScan.h"

View File

@ -3625,6 +3625,19 @@ class LCallSetElement : public LCallInstructionHelper<0, 1 + 2 * BOX_PIECES, 0>
static const size_t Value = 1 + BOX_PIECES;
};
// Call js::InitElementArray.
class LCallInitElementArray : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
{
public:
LIR_HEADER(CallInitElementArray)
static const size_t Value = 1;
const MCallInitElementArray *mir() const {
return mir_->toCallInitElementArray();
}
};
// Call a VM function to perform a property or name assignment of a generic value.
class LCallSetProperty : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
{

View File

@ -15,7 +15,6 @@
#include "InlineList.h"
#include "FixedArityList.h"
#include "LOpcodes.h"
#include "TypeOracle.h"
#include "Registers.h"
#include "MIR.h"
#include "MIRGraph.h"

View File

@ -130,7 +130,7 @@
_(LoadSlotT) \
_(StoreSlotV) \
_(StoreSlotT) \
_(GuardShape) \
_(GuardShapeOrType) \
_(GuardClass) \
_(ParWriteGuard) \
_(ParDump) \
@ -178,6 +178,7 @@
_(CallsiteCloneCache) \
_(CallGetElement) \
_(CallSetElement) \
_(CallInitElementArray) \
_(CallSetProperty) \
_(CallDeleteProperty) \
_(SetPropertyCacheV) \

View File

@ -2309,6 +2309,16 @@ LIRGenerator::visitCallSetElement(MCallSetElement *ins)
return add(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitCallInitElementArray(MCallInitElementArray *ins)
{
LCallInitElementArray *lir = new LCallInitElementArray();
lir->setOperand(0, useRegisterAtStart(ins->object()));
if (!useBoxAtStart(lir, LCallInitElementArray::Value, ins->value()))
return false;
return add(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitIteratorStart(MIteratorStart *ins)
{

View File

@ -202,6 +202,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitCallsiteCloneCache(MCallsiteCloneCache *ins);
bool visitCallGetElement(MCallGetElement *ins);
bool visitCallSetElement(MCallSetElement *ins);
bool visitCallInitElementArray(MCallInitElementArray *ins);
bool visitSetPropertyCache(MSetPropertyCache *ins);
bool visitCallSetProperty(MCallSetProperty *ins);
bool visitIteratorStart(MIteratorStart *ins);

View File

@ -119,10 +119,7 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
types::StackTypeSet *
IonBuilder::getInlineReturnTypeSet()
{
types::StackTypeSet *barrier;
types::StackTypeSet *returnTypes = oracle->returnTypeSet(script(), pc, &barrier);
JS_ASSERT(returnTypes);
return returnTypes;
return script()->analysis()->bytecodeTypes(pc);
}
MIRType
@ -132,36 +129,6 @@ IonBuilder::getInlineReturnType()
return MIRTypeFromValueType(returnTypes->getKnownTypeTag());
}
types::StackTypeSet *
IonBuilder::getInlineThisTypeSet(CallInfo &callInfo)
{
types::StackTypeSet *thisTypes = oracle->getCallArg(script(), callInfo.argc(), 0, pc);
JS_ASSERT(thisTypes);
return thisTypes;
}
MIRType
IonBuilder::getInlineThisType(CallInfo &callInfo)
{
types::StackTypeSet *argTypes = getInlineThisTypeSet(callInfo);
return MIRTypeFromValueType(argTypes->getKnownTypeTag());
}
types::StackTypeSet *
IonBuilder::getInlineArgTypeSet(CallInfo &callInfo, uint32_t arg)
{
types::StackTypeSet *argTypes = oracle->getCallArg(script(), callInfo.argc(), arg + 1, pc);
JS_ASSERT(argTypes);
return argTypes;
}
MIRType
IonBuilder::getInlineArgType(CallInfo &callInfo, uint32_t arg)
{
types::StackTypeSet *argTypes = getInlineArgTypeSet(callInfo, arg);
return MIRTypeFromValueType(argTypes->getKnownTypeTag());
}
IonBuilder::InliningStatus
IonBuilder::inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function)
{
@ -173,7 +140,7 @@ IonBuilder::inlineMathFunction(CallInfo &callInfo, MMathFunction::Function funct
if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined;
if (!IsNumberType(getInlineArgType(callInfo, 0)))
if (!IsNumberType(callInfo.getArg(0)->type()))
return InliningStatus_NotInlined;
callInfo.unwrapArgs();
@ -198,11 +165,28 @@ IonBuilder::inlineArray(CallInfo &callInfo)
if (callInfo.argc() >= 2) {
initLength = callInfo.argc();
allocating = MNewArray::NewArray_Allocating;
types::TypeObject *type = types::TypeScript::InitObject(cx, script(), pc, JSProto_Array);
if (!type)
return InliningStatus_Error;
if (!type->unknownProperties()) {
types::HeapTypeSet *elemTypes = type->getProperty(cx, JSID_VOID, false);
if (!elemTypes)
return InliningStatus_Error;
for (uint32_t i = 0; i < initLength; i++) {
MDefinition *value = callInfo.getArg(i);
if (!TypeSetIncludes(elemTypes, value->type(), value->resultTypeSet())) {
elemTypes->addFreeze(cx);
return InliningStatus_NotInlined;
}
}
}
}
// A single integer argument denotes initial length.
if (callInfo.argc() == 1) {
if (getInlineArgType(callInfo, 0) != MIRType_Int32)
if (callInfo.getArg(0)->type() != MIRType_Int32)
return InliningStatus_NotInlined;
MDefinition *arg = callInfo.getArg(0)->toPassArg()->getArgument();
if (!arg->isConstant())
@ -220,8 +204,9 @@ IonBuilder::inlineArray(CallInfo &callInfo)
if (!templateObject)
return InliningStatus_Error;
bool convertDoubles = oracle->arrayResultShouldHaveDoubleConversion(script(), pc);
if (convertDoubles)
types::StackTypeSet::DoubleConversion conversion =
getInlineReturnTypeSet()->convertDoubleElements(cx);
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles)
templateObject->setShouldConvertDoubleElements();
MNewArray *ins = new MNewArray(initLength, templateObject, allocating);
@ -242,7 +227,7 @@ IonBuilder::inlineArray(CallInfo &callInfo)
current->add(id);
MDefinition *value = callInfo.getArg(i);
if (convertDoubles) {
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles) {
MInstruction *valueDouble = MToDouble::New(value);
current->add(valueDouble);
value = valueDouble;
@ -273,22 +258,19 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
MIRType returnType = getInlineReturnType();
if (returnType == MIRType_Undefined || returnType == MIRType_Null)
return InliningStatus_NotInlined;
if (getInlineThisType(callInfo) != MIRType_Object)
if (callInfo.thisArg()->type() != MIRType_Object)
return InliningStatus_NotInlined;
// Pop and shift are only handled for dense arrays that have never been
// used in an iterator: popping elements does not account for suppressing
// deleted properties in active iterators.
//
// Inference's TypeConstraintCall generates the constraints that propagate
// properties directly into the result type set.
types::TypeObjectFlags unhandledFlags =
types::OBJECT_FLAG_SPARSE_INDEXES |
types::OBJECT_FLAG_LENGTH_OVERFLOW |
types::OBJECT_FLAG_ITERATED;
types::StackTypeSet *thisTypes = getInlineThisTypeSet(callInfo);
if (thisTypes->getKnownClass() != &ArrayClass)
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
if (!thisTypes || thisTypes->getKnownClass() != &ArrayClass)
return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(cx, unhandledFlags))
return InliningStatus_NotInlined;
@ -302,6 +284,10 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
bool needsHoleCheck = thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
bool barrier = PropertyReadNeedsTypeBarrier(cx, callInfo.thisArg(), NULL, returnTypes);
if (barrier)
returnType = MIRType_Value;
MArrayPopShift *ins = MArrayPopShift::New(callInfo.thisArg(), mode,
needsHoleCheck, maybeUndefined);
current->add(ins);
@ -310,6 +296,10 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
if (!resumeAfter(ins))
return InliningStatus_Error;
if (!pushTypeBarrier(ins, returnTypes, barrier))
return InliningStatus_Error;
return InliningStatus_Inlined;
}
@ -319,15 +309,20 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo)
if (callInfo.argc() != 1 || callInfo.constructing())
return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Int32)
MDefinition *obj = callInfo.thisArg();
MDefinition *value = callInfo.getArg(0);
if (PropertyWriteNeedsTypeBarrier(cx, current, &obj, NULL, &value))
return InliningStatus_NotInlined;
if (getInlineThisType(callInfo) != MIRType_Object)
if (obj != callInfo.thisArg() || value != callInfo.getArg(0))
return InliningStatus_NotInlined;
// Inference's TypeConstraintCall generates the constraints that propagate
// properties directly into the result type set.
types::StackTypeSet *thisTypes = getInlineThisTypeSet(callInfo);
if (thisTypes->getKnownClass() != &ArrayClass)
if (getInlineReturnType() != MIRType_Int32)
return InliningStatus_NotInlined;
if (callInfo.thisArg()->type() != MIRType_Object)
return InliningStatus_NotInlined;
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
if (!thisTypes || thisTypes->getKnownClass() != &ArrayClass)
return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES |
types::OBJECT_FLAG_LENGTH_OVERFLOW))
@ -343,8 +338,8 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo)
return InliningStatus_NotInlined;
callInfo.unwrapArgs();
value = callInfo.getArg(0);
MDefinition *value = callInfo.getArg(0);
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles ||
conversion == types::StackTypeSet::MaybeConvertToDoubles)
{
@ -371,14 +366,16 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
// Ensure |this|, argument and result are objects.
if (getInlineReturnType() != MIRType_Object)
return InliningStatus_NotInlined;
if (getInlineThisType(callInfo) != MIRType_Object)
if (callInfo.thisArg()->type() != MIRType_Object)
return InliningStatus_NotInlined;
if (getInlineArgType(callInfo, 0) != MIRType_Object)
if (callInfo.getArg(0)->type() != MIRType_Object)
return InliningStatus_NotInlined;
// |this| and the argument must be dense arrays.
types::StackTypeSet *thisTypes = getInlineThisTypeSet(callInfo);
types::StackTypeSet *argTypes = getInlineArgTypeSet(callInfo, 0);
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
types::StackTypeSet *argTypes = callInfo.getArg(0)->resultTypeSet();
if (!thisTypes || !argTypes)
return InliningStatus_NotInlined;
if (thisTypes->getKnownClass() != &ArrayClass)
return InliningStatus_NotInlined;
@ -407,8 +404,12 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
return InliningStatus_NotInlined;
types::TypeObject *thisType = thisTypes->getTypeObject(0);
if (!thisType || &thisType->proto->global() != &script->global())
if (!thisType ||
thisType->unknownProperties() ||
&thisType->proto->global() != &script->global())
{
return InliningStatus_NotInlined;
}
// Constraints modeling this concat have not been generated by inference,
// so check that type information already reflects possible side effects of
@ -429,6 +430,9 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
if (!argType)
continue;
if (argType->unknownProperties())
return InliningStatus_NotInlined;
types::HeapTypeSet *elemTypes = argType->getProperty(cx, JSID_VOID, false);
if (!elemTypes)
return InliningStatus_Error;
@ -464,7 +468,7 @@ IonBuilder::inlineMathAbs(CallInfo &callInfo)
return InliningStatus_NotInlined;
MIRType returnType = getInlineReturnType();
MIRType argType = getInlineArgType(callInfo, 0);
MIRType argType = callInfo.getArg(0)->type();
if (argType != MIRType_Int32 && argType != MIRType_Double)
return InliningStatus_NotInlined;
@ -497,7 +501,7 @@ IonBuilder::inlineMathFloor(CallInfo &callInfo)
if (callInfo.argc() != 1)
return InliningStatus_NotInlined;
MIRType argType = getInlineArgType(callInfo, 0);
MIRType argType = callInfo.getArg(0)->type();
if (getInlineReturnType() != MIRType_Int32)
return InliningStatus_NotInlined;
@ -529,7 +533,7 @@ IonBuilder::inlineMathRound(CallInfo &callInfo)
return InliningStatus_NotInlined;
MIRType returnType = getInlineReturnType();
MIRType argType = getInlineArgType(callInfo, 0);
MIRType argType = callInfo.getArg(0)->type();
// Math.round(int(x)) == int(x)
if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
@ -558,7 +562,7 @@ IonBuilder::inlineMathSqrt(CallInfo &callInfo)
if (callInfo.argc() != 1)
return InliningStatus_NotInlined;
MIRType argType = getInlineArgType(callInfo, 0);
MIRType argType = callInfo.getArg(0)->type();
if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined;
if (argType != MIRType_Double && argType != MIRType_Int32)
@ -582,8 +586,8 @@ IonBuilder::inlineMathPow(CallInfo &callInfo)
return InliningStatus_NotInlined;
// Typechecking.
MIRType baseType = getInlineArgType(callInfo, 0);
MIRType powerType = getInlineArgType(callInfo, 1);
MIRType baseType = callInfo.getArg(0)->type();
MIRType powerType = callInfo.getArg(1)->type();
MIRType outputType = getInlineReturnType();
if (outputType != MIRType_Int32 && outputType != MIRType_Double)
@ -703,9 +707,9 @@ IonBuilder::inlineMathImul(CallInfo &callInfo)
if (returnType != MIRType_Int32)
return InliningStatus_NotInlined;
if (!IsNumberType(getInlineArgType(callInfo, 0)))
if (!IsNumberType(callInfo.getArg(0)->type()))
return InliningStatus_NotInlined;
if (!IsNumberType(getInlineArgType(callInfo, 1)))
if (!IsNumberType(callInfo.getArg(1)->type()))
return InliningStatus_NotInlined;
callInfo.unwrapArgs();
@ -732,10 +736,10 @@ IonBuilder::inlineMathMinMax(CallInfo &callInfo, bool max)
if (!IsNumberType(returnType))
return InliningStatus_NotInlined;
MIRType arg0Type = getInlineArgType(callInfo, 0);
MIRType arg0Type = callInfo.getArg(0)->type();
if (!IsNumberType(arg0Type))
return InliningStatus_NotInlined;
MIRType arg1Type = getInlineArgType(callInfo, 1);
MIRType arg1Type = callInfo.getArg(1)->type();
if (!IsNumberType(arg1Type))
return InliningStatus_NotInlined;
@ -761,7 +765,7 @@ IonBuilder::inlineStringObject(CallInfo &callInfo)
return InliningStatus_NotInlined;
// MToString only supports int32 or string values.
MIRType type = getInlineArgType(callInfo, 0);
MIRType type = callInfo.getArg(0)->type();
if (type != MIRType_Int32 && type != MIRType_String)
return InliningStatus_NotInlined;
@ -790,9 +794,9 @@ IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo)
if (getInlineReturnType() != MIRType_Int32)
return InliningStatus_NotInlined;
if (getInlineThisType(callInfo) != MIRType_String)
if (callInfo.thisArg()->type() != MIRType_String && callInfo.thisArg()->type() != MIRType_Value)
return InliningStatus_NotInlined;
MIRType argType = getInlineArgType(callInfo, 0);
MIRType argType = callInfo.getArg(0)->type();
if (argType != MIRType_Int32 && argType != MIRType_Double)
return InliningStatus_NotInlined;
@ -820,7 +824,7 @@ IonBuilder::inlineStrFromCharCode(CallInfo &callInfo)
if (getInlineReturnType() != MIRType_String)
return InliningStatus_NotInlined;
if (getInlineArgType(callInfo, 0) != MIRType_Int32)
if (callInfo.getArg(0)->type() != MIRType_Int32)
return InliningStatus_NotInlined;
callInfo.unwrapArgs();
@ -842,9 +846,9 @@ IonBuilder::inlineStrCharAt(CallInfo &callInfo)
if (getInlineReturnType() != MIRType_String)
return InliningStatus_NotInlined;
if (getInlineThisType(callInfo) != MIRType_String)
if (callInfo.thisArg()->type() != MIRType_String)
return InliningStatus_NotInlined;
MIRType argType = getInlineArgType(callInfo, 0);
MIRType argType = callInfo.getArg(0)->type();
if (argType != MIRType_Int32 && argType != MIRType_Double)
return InliningStatus_NotInlined;
@ -878,12 +882,13 @@ IonBuilder::inlineRegExpTest(CallInfo &callInfo)
if (CallResultEscapes(pc) && getInlineReturnType() != MIRType_Boolean)
return InliningStatus_NotInlined;
if (getInlineThisType(callInfo) != MIRType_Object)
if (callInfo.thisArg()->type() != MIRType_Object)
return InliningStatus_NotInlined;
Class *clasp = getInlineThisTypeSet(callInfo)->getKnownClass();
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
Class *clasp = thisTypes ? thisTypes->getKnownClass() : NULL;
if (clasp != &RegExpClass)
return InliningStatus_NotInlined;
if (getInlineArgType(callInfo, 0) != MIRType_String)
if (callInfo.getArg(0)->type() != MIRType_String)
return InliningStatus_NotInlined;
callInfo.unwrapArgs();
@ -915,13 +920,24 @@ IonBuilder::inlineUnsafeSetElement(CallInfo &callInfo)
for (uint32_t base = 0; base < argc; base += 3) {
uint32_t arri = base + 0;
uint32_t idxi = base + 1;
uint32_t elemi = base + 2;
types::StackTypeSet *obj = getInlineArgTypeSet(callInfo, arri);
types::StackTypeSet *id = getInlineArgTypeSet(callInfo, idxi);
MDefinition *obj = callInfo.getArg(arri);
MDefinition *id = callInfo.getArg(idxi);
MDefinition *elem = callInfo.getArg(elemi);
if (PropertyWriteNeedsTypeBarrier(cx, current, &obj, NULL, &elem))
return InliningStatus_NotInlined;
int arrayType;
if (!oracle->elementWriteIsDenseNative(obj, id) &&
!oracle->elementWriteIsTypedArray(obj, id, &arrayType))
if (!ElementAccessIsDenseNative(obj, id) &&
!ElementAccessIsTypedArray(obj, id, &arrayType))
{
return InliningStatus_NotInlined;
}
if (obj->resultTypeSet()->convertDoubleElements(cx) !=
types::StackTypeSet::DontConvertToDoubles)
{
return InliningStatus_NotInlined;
}
@ -939,17 +955,17 @@ IonBuilder::inlineUnsafeSetElement(CallInfo &callInfo)
uint32_t arri = base + 0;
uint32_t idxi = base + 1;
types::StackTypeSet *obj = getInlineArgTypeSet(callInfo, arri);
types::StackTypeSet *id = getInlineArgTypeSet(callInfo, idxi);
MDefinition *obj = callInfo.getArg(arri);
MDefinition *id = callInfo.getArg(idxi);
if (oracle->elementWriteIsDenseNative(obj, id)) {
if (ElementAccessIsDenseNative(obj, id)) {
if (!inlineUnsafeSetDenseArrayElement(callInfo, base))
return InliningStatus_Error;
continue;
}
int arrayType;
if (oracle->elementWriteIsTypedArray(obj, id, &arrayType)) {
if (ElementAccessIsTypedArray(obj, id, &arrayType)) {
if (!inlineUnsafeSetTypedArrayElement(callInfo, base, arrayType))
return InliningStatus_Error;
continue;
@ -968,8 +984,8 @@ IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base)
// in intrinsic_UnsafeSetElement():
// - arr is a dense array
// - idx < initialized length
// Furthermore, note that inference should be propagating
// the type of the value to the JSID_VOID property of the array.
// Furthermore, note that inlineUnsafeSetElement ensures the type of the
// value is reflected in the JSID_VOID property of the array.
uint32_t arri = base + 0;
uint32_t idxi = base + 1;
@ -990,7 +1006,7 @@ IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base)
/* needsHoleCheck = */ false);
store->setRacy();
if (oracle->elementWriteNeedsBarrier(getInlineArgTypeSet(callInfo, arri)))
if (callInfo.getArg(arri)->resultTypeSet()->propertyNeedsBarrier(cx, JSID_VOID))
store->setNeedsBarrier();
current->add(store);
@ -1011,9 +1027,9 @@ IonBuilder::inlineUnsafeSetTypedArrayElement(CallInfo &callInfo,
// - arr is a typed array
// - idx < length
uint32_t arri = base + 1;
uint32_t idxi = base + 2;
uint32_t elemi = base + 3;
uint32_t arri = base + 0;
uint32_t idxi = base + 1;
uint32_t elemi = base + 2;
MInstruction *elements = getTypedArrayElements(callInfo.getArg(arri));
current->add(elements);
@ -1081,8 +1097,8 @@ IonBuilder::inlineNewParallelArray(CallInfo &callInfo)
if (argc < 1 || callInfo.constructing())
return InliningStatus_NotInlined;
types::StackTypeSet *ctorTypes = getInlineArgTypeSet(callInfo, 0);
RawObject targetObj = ctorTypes->getSingleton();
types::StackTypeSet *ctorTypes = callInfo.getArg(0)->resultTypeSet();
RawObject targetObj = ctorTypes ? ctorTypes->getSingleton() : NULL;
RootedFunction target(cx);
if (targetObj && targetObj->isFunction())
target = targetObj->toFunction();
@ -1152,7 +1168,7 @@ IonBuilder::inlineParallelArrayTail(CallInfo &callInfo,
if (target && !target->isNative())
targetArgs = Max<uint32_t>(target->nargs, argc);
MCall *call = MCall::New(target, targetArgs + 1, argc, false, ctorTypes);
MCall *call = MCall::New(target, targetArgs + 1, argc, false);
if (!call)
return InliningStatus_Error;
@ -1296,7 +1312,7 @@ IonBuilder::inlineThrowError(CallInfo &callInfo)
return InliningStatus_Error;
current->end(bailout);
current = newBlock(pc);
setCurrentAndSpecializePhis(newBlock(pc));
if (!current)
return InliningStatus_Error;
@ -1315,7 +1331,7 @@ IonBuilder::inlineIsCallable(CallInfo &callInfo)
if (getInlineReturnType() != MIRType_Boolean)
return InliningStatus_NotInlined;
if (getInlineArgType(callInfo, 0) != MIRType_Object)
if (callInfo.getArg(0)->type() != MIRType_Object)
return InliningStatus_NotInlined;
callInfo.unwrapArgs();
@ -1336,18 +1352,12 @@ IonBuilder::inlineToObject(CallInfo &callInfo)
// If we know the input type is an object, nop ToObject.
if (getInlineReturnType() != MIRType_Object)
return InliningStatus_NotInlined;
if (getInlineArgType(callInfo, 0) != MIRType_Object)
if (callInfo.getArg(0)->type() != MIRType_Object)
return InliningStatus_NotInlined;
callInfo.unwrapArgs();
MDefinition *object = callInfo.getArg(0);
// TI still expects the barrier to be checked, since this was a native
// call. We manually make a MTypeBarrier here to avoid pointless
// boxing-unbox sequences.
MTypeBarrier *barrier = MTypeBarrier::New(object, cloneTypeSet(callInfo.barrier()));
current->add(barrier);
current->push(object);
return InliningStatus_Inlined;
}

View File

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BaselineInspector.h"
#include "IonBuilder.h"
#include "LICM.h" // For LinearSum
#include "MIR.h"
@ -182,22 +183,26 @@ MDefinition::analyzeEdgeCasesBackward()
}
static bool
MaybeEmulatesUndefined(types::StackTypeSet *types, JSContext *cx)
MaybeEmulatesUndefined(JSContext *cx, MDefinition *op)
{
if (!op->mightBeType(MIRType_Object))
return false;
types::StackTypeSet *types = op->resultTypeSet();
if (!types)
return true;
if (!types->maybeObject())
return false;
return types->hasObjectFlags(cx, types::OBJECT_FLAG_EMULATES_UNDEFINED);
}
void
MTest::infer(const TypeOracle::UnaryTypes &u, JSContext *cx)
MTest::infer(JSContext *cx)
{
if (!u.inTypes)
return;
JS_ASSERT(operandMightEmulateUndefined());
if (!MaybeEmulatesUndefined(u.inTypes, cx))
if (!MaybeEmulatesUndefined(cx, getOperand(0)))
markOperandCantEmulateUndefined();
}
@ -319,10 +324,28 @@ MConstant::New(const Value &v)
return new MConstant(v);
}
types::StackTypeSet *
ion::MakeSingletonTypeSet(JSObject *obj)
{
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
types::StackTypeSet *types = alloc->new_<types::StackTypeSet>();
if (!types)
return NULL;
types::Type objectType = types::Type::ObjectType(obj);
types->addObject(objectType.objectKey(), alloc);
return types;
}
MConstant::MConstant(const js::Value &vp)
: 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.
setResultTypeSet(MakeSingletonTypeSet(&vp.toObject()));
}
setMovable();
}
@ -402,7 +425,7 @@ MConstantElements::printOpcode(FILE *fp)
}
MParameter *
MParameter::New(int32_t index, const types::StackTypeSet *types)
MParameter::New(int32_t index, types::StackTypeSet *types)
{
return new MParameter(index, types);
}
@ -430,11 +453,10 @@ MParameter::congruentTo(MDefinition * const &ins) const
}
MCall *
MCall::New(JSFunction *target, size_t maxArgc, size_t numActualArgs, bool construct,
types::StackTypeSet *calleeTypes)
MCall::New(JSFunction *target, size_t maxArgc, size_t numActualArgs, bool construct)
{
JS_ASSERT(maxArgc >= numActualArgs);
MCall *ins = new MCall(target, numActualArgs, construct, calleeTypes);
MCall *ins = new MCall(target, numActualArgs, construct);
if (!ins->init(maxArgc + NumNonArgumentOperands))
return NULL;
return ins;
@ -601,6 +623,120 @@ MPhi::reserveLength(size_t length)
return inputs_.reserve(length);
}
static inline types::StackTypeSet *
MakeMIRTypeSet(MIRType type)
{
JS_ASSERT(type != MIRType_Value);
types::Type ntype = type == MIRType_Object
? types::Type::AnyObjectType()
: types::Type::PrimitiveType(ValueTypeFromMIRType(type));
return GetIonContext()->temp->lifoAlloc()->new_<types::StackTypeSet>(ntype);
}
void
ion::MergeTypes(MIRType *ptype, types::StackTypeSet **ptypeSet,
MIRType newType, types::StackTypeSet *newTypeSet)
{
if (newTypeSet && newTypeSet->empty())
return;
if (newType != *ptype) {
if (IsNumberType(newType) && IsNumberType(*ptype)) {
*ptype = MIRType_Double;
} else if (*ptype != MIRType_Value) {
if (!*ptypeSet)
*ptypeSet = MakeMIRTypeSet(*ptype);
*ptype = MIRType_Value;
}
}
if (*ptypeSet) {
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
if (!newTypeSet && newType != MIRType_Value)
newTypeSet = MakeMIRTypeSet(newType);
if (newTypeSet) {
if (!newTypeSet->isSubset(*ptypeSet))
*ptypeSet = types::TypeSet::unionSets(*ptypeSet, newTypeSet, alloc);
} else {
*ptypeSet = NULL;
}
}
}
void
MPhi::specializeType()
{
#ifdef DEBUG
JS_ASSERT(!specialized_);
specialized_ = true;
#endif
JS_ASSERT(!inputs_.empty());
size_t start;
if (hasBackedgeType_) {
// The type of this phi has already been populated with potential types
// that could come in via loop backedges.
start = 0;
} else {
setResultType(getOperand(0)->type());
setResultTypeSet(getOperand(0)->resultTypeSet());
start = 1;
}
MIRType resultType = this->type();
types::StackTypeSet *resultTypeSet = this->resultTypeSet();
for (size_t i = start; i < inputs_.length(); i++) {
MDefinition *def = getOperand(i);
MergeTypes(&resultType, &resultTypeSet, def->type(), def->resultTypeSet());
}
setResultType(resultType);
setResultTypeSet(resultTypeSet);
}
void
MPhi::addBackedgeType(MIRType type, types::StackTypeSet *typeSet)
{
JS_ASSERT(!specialized_);
if (hasBackedgeType_) {
MIRType resultType = this->type();
types::StackTypeSet *resultTypeSet = this->resultTypeSet();
MergeTypes(&resultType, &resultTypeSet, type, typeSet);
setResultType(resultType);
setResultTypeSet(resultTypeSet);
} else {
setResultType(type);
setResultTypeSet(typeSet);
hasBackedgeType_ = true;
}
}
bool
MPhi::typeIncludes(MDefinition *def)
{
if (def->type() == MIRType_Int32 && this->type() == MIRType_Double)
return true;
if (types::StackTypeSet *types = def->resultTypeSet()) {
if (this->resultTypeSet())
return types->isSubset(this->resultTypeSet());
if (this->type() == MIRType_Value || types->empty())
return true;
return this->type() == MIRTypeFromValueType(types->getKnownTypeTag());
}
if (def->type() == MIRType_Value) {
// This phi must be able to be any value.
return this->type() == MIRType_Value
&& (!this->resultTypeSet() || this->resultTypeSet()->unknown());
}
return this->mightBeType(def->type());
}
void
MPhi::addInput(MDefinition *ins)
{
@ -614,7 +750,7 @@ MPhi::addInput(MDefinition *ins)
}
bool
MPhi::addInputSlow(MDefinition *ins)
MPhi::addInputSlow(MDefinition *ins, bool *ptypeChange)
{
// The list of inputs to an MPhi is given as a vector of MUse nodes,
// each of which is in the list of the producer MDefinition.
@ -636,8 +772,22 @@ MPhi::addInputSlow(MDefinition *ins)
// Insert the new input.
if (!inputs_.append(MUse()))
return false;
MPhi::setOperand(index, ins);
if (ptypeChange) {
MIRType resultType = this->type();
types::StackTypeSet *resultTypeSet = this->resultTypeSet();
MergeTypes(&resultType, &resultTypeSet, ins->type(), ins->resultTypeSet());
if (resultType != this->type() || resultTypeSet != this->resultTypeSet()) {
*ptypeChange = true;
setResultType(resultType);
setResultTypeSet(resultTypeSet);
}
}
// Add all previously-removed MUses back.
if (performingRealloc) {
for (uint32_t i = 0; i < index; i++) {
@ -679,9 +829,9 @@ MCall::addArg(size_t argnum, MPassArg *arg)
}
void
MBitNot::infer(const TypeOracle::UnaryTypes &u)
MBitNot::infer()
{
if (u.inTypes->maybeObject())
if (getOperand(0)->mightBeType(MIRType_Object))
specialization_ = MIRType_None;
else
specialization_ = MIRType_Int32;
@ -724,9 +874,9 @@ MBinaryBitwiseInstruction::foldsTo(bool useValueNumbers)
}
void
MBinaryBitwiseInstruction::infer(const TypeOracle::BinaryTypes &b)
MBinaryBitwiseInstruction::infer()
{
if (b.lhsTypes->maybeObject() || b.rhsTypes->maybeObject()) {
if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object)) {
specialization_ = MIRType_None;
} else {
specialization_ = MIRType_Int32;
@ -743,31 +893,30 @@ MBinaryBitwiseInstruction::specializeForAsmJS()
}
void
MShiftInstruction::infer(const TypeOracle::BinaryTypes &b)
MShiftInstruction::infer()
{
if (b.lhsTypes->maybeObject() || b.rhsTypes->maybeObject())
if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object))
specialization_ = MIRType_None;
else
specialization_ = MIRType_Int32;
}
void
MUrsh::infer(const TypeOracle::BinaryTypes &b)
MUrsh::infer()
{
if (b.lhsTypes->maybeObject() || b.rhsTypes->maybeObject()) {
if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object)) {
specialization_ = MIRType_None;
setResultType(MIRType_Value);
return;
}
if (b.outTypes->getKnownTypeTag() == JSVAL_TYPE_DOUBLE) {
specialization_ = MIRType_Double;
setResultType(MIRType_Double);
if (type() == MIRType_Int32) {
specialization_ = MIRType_Int32;
return;
}
specialization_ = MIRType_Int32;
JS_ASSERT(type() == MIRType_Int32);
specialization_ = MIRType_Double;
setResultType(MIRType_Double);
}
static inline bool
@ -1078,42 +1227,47 @@ MMul::canOverflow()
return !range() || !range()->isInt32();
}
void
MBinaryArithInstruction::infer(const TypeOracle::BinaryTypes &b, JSContext *cx)
static inline bool
KnownNonStringPrimitive(MDefinition *op)
{
// Retrieve type information of lhs and rhs
// Rhs is defaulted to int32 first,
// because in some cases there is no rhs type information
MIRType lhs = MIRTypeFromValueType(b.lhsTypes->getKnownTypeTag());
MIRType rhs = MIRType_Int32;
return !op->mightBeType(MIRType_Object)
&& !op->mightBeType(MIRType_String)
&& !op->mightBeType(MIRType_Magic);
}
// Test if types coerces to doubles
bool lhsCoerces = b.lhsTypes->knownNonStringPrimitive();
bool rhsCoerces = true;
void
MBinaryArithInstruction::infer(bool overflowed)
{
JS_ASSERT(this->type() == MIRType_Value);
// Use type information provided by oracle if available.
if (b.rhsTypes) {
rhs = MIRTypeFromValueType(b.rhsTypes->getKnownTypeTag());
rhsCoerces = b.rhsTypes->knownNonStringPrimitive();
}
specialization_ = MIRType_None;
MIRType rval = MIRTypeFromValueType(b.outTypes->getKnownTypeTag());
// Don't specialize for neither-integer-nor-double results.
if (rval != MIRType_Int32 && rval != MIRType_Double) {
specialization_ = MIRType_None;
return;
}
// Retrieve type information of lhs and rhs.
MIRType lhs = getOperand(0)->type();
MIRType rhs = getOperand(1)->type();
// Anything complex - strings and objects - are not specialized.
if (!lhsCoerces || !rhsCoerces) {
specialization_ = MIRType_None;
if (!KnownNonStringPrimitive(getOperand(0)) || !KnownNonStringPrimitive(getOperand(1)))
return;
}
// Guess a result type based on the inputs.
// Don't specialize for neither-integer-nor-double results.
if (lhs == MIRType_Int32 && rhs == MIRType_Int32)
setResultType(MIRType_Int32);
else if (lhs == MIRType_Double || rhs == MIRType_Double)
setResultType(MIRType_Double);
else
return;
// If the operation has ever overflowed, use a double specialization.
if (overflowed)
setResultType(MIRType_Double);
JS_ASSERT(lhs < MIRType_String || lhs == MIRType_Value);
JS_ASSERT(rhs < MIRType_String || rhs == MIRType_Value);
MIRType rval = this->type();
// Don't specialize values when result isn't double
if (lhs == MIRType_Value || rhs == MIRType_Value) {
if (rval != MIRType_Double) {
@ -1137,47 +1291,33 @@ MBinaryArithInstruction::infer(const TypeOracle::BinaryTypes &b, JSContext *cx)
}
static bool
SafelyCoercesToDouble(JSContext *cx, types::StackTypeSet *types)
SafelyCoercesToDouble(MDefinition *op)
{
types::TypeFlags flags = types->baseFlags();
// Strings are unhandled -- visitToDouble() doesn't support them yet.
// Null is unhandled -- ToDouble(null) == 0, but (0 == null) is false.
types::TypeFlags converts = types::TYPE_FLAG_UNDEFINED | types::TYPE_FLAG_DOUBLE |
types::TYPE_FLAG_INT32 | types::TYPE_FLAG_BOOLEAN;
if ((flags & converts) == flags)
return true;
return false;
return KnownNonStringPrimitive(op) && !op->mightBeType(MIRType_Null);
}
static bool
CanDoValueBitwiseCmp(JSContext *cx, types::StackTypeSet *lhs, types::StackTypeSet *rhs, bool looseEq)
ObjectOrSimplePrimitive(MDefinition *op)
{
// Return true if op is either undefined/null/bolean/int32 or an object.
return !op->mightBeType(MIRType_String)
&& !op->mightBeType(MIRType_Double)
&& !op->mightBeType(MIRType_Magic);
}
static bool
CanDoValueBitwiseCmp(JSContext *cx, MDefinition *lhs, MDefinition *rhs, bool looseEq)
{
// Only primitive (not double/string) or objects are supported.
// I.e. Undefined/Null/Boolean/Int32 and Object
if (!lhs->knownPrimitiveOrObject() ||
lhs->hasAnyFlag(types::TYPE_FLAG_STRING) ||
lhs->hasAnyFlag(types::TYPE_FLAG_DOUBLE) ||
!rhs->knownPrimitiveOrObject() ||
rhs->hasAnyFlag(types::TYPE_FLAG_STRING) ||
rhs->hasAnyFlag(types::TYPE_FLAG_DOUBLE))
{
if (!ObjectOrSimplePrimitive(lhs) || !ObjectOrSimplePrimitive(rhs))
return false;
}
// Objects that emulate undefined are not supported.
if (lhs->maybeObject() &&
lhs->hasObjectFlags(cx, types::OBJECT_FLAG_EMULATES_UNDEFINED))
{
if (MaybeEmulatesUndefined(cx, lhs) || MaybeEmulatesUndefined(cx, rhs))
return false;
}
if (rhs->maybeObject() &&
rhs->hasObjectFlags(cx, types::OBJECT_FLAG_EMULATES_UNDEFINED))
{
return false;
}
// In the loose comparison more values could be the same,
// but value comparison reporting otherwise.
@ -1185,30 +1325,26 @@ CanDoValueBitwiseCmp(JSContext *cx, types::StackTypeSet *lhs, types::StackTypeSe
// Undefined compared loosy to Null is not supported,
// because tag is different, but value can be the same (undefined == null).
if ((lhs->hasAnyFlag(types::TYPE_FLAG_UNDEFINED) &&
rhs->hasAnyFlag(types::TYPE_FLAG_NULL)) ||
(lhs->hasAnyFlag(types::TYPE_FLAG_NULL) &&
rhs->hasAnyFlag(types::TYPE_FLAG_UNDEFINED)))
if ((lhs->mightBeType(MIRType_Undefined) && rhs->mightBeType(MIRType_Null)) ||
(lhs->mightBeType(MIRType_Null) && rhs->mightBeType(MIRType_Undefined)))
{
return false;
}
// Int32 compared loosy to Boolean is not supported,
// because tag is different, but value can be the same (1 == true).
if ((lhs->hasAnyFlag(types::TYPE_FLAG_INT32) &&
rhs->hasAnyFlag(types::TYPE_FLAG_BOOLEAN)) ||
(lhs->hasAnyFlag(types::TYPE_FLAG_BOOLEAN) &&
rhs->hasAnyFlag(types::TYPE_FLAG_INT32)))
if ((lhs->mightBeType(MIRType_Int32) && rhs->mightBeType(MIRType_Boolean)) ||
(lhs->mightBeType(MIRType_Boolean) && rhs->mightBeType(MIRType_Int32)))
{
return false;
}
// For loosy comparison of an object with a Boolean/Number/String
// the valueOf the object is taken. Therefore not supported.
types::TypeFlags numbers = types::TYPE_FLAG_BOOLEAN |
types::TYPE_FLAG_INT32;
if ((lhs->maybeObject() && rhs->hasAnyFlag(numbers)) ||
(rhs->maybeObject() && lhs->hasAnyFlag(numbers)))
bool simpleLHS = lhs->mightBeType(MIRType_Boolean) || lhs->mightBeType(MIRType_Int32);
bool simpleRHS = rhs->mightBeType(MIRType_Boolean) || rhs->mightBeType(MIRType_Int32);
if ((lhs->mightBeType(MIRType_Object) && simpleRHS) ||
(rhs->mightBeType(MIRType_Object) && simpleLHS))
{
return false;
}
@ -1247,18 +1383,15 @@ MCompare::inputType()
}
void
MCompare::infer(const TypeOracle::BinaryTypes &b, JSContext *cx)
MCompare::infer(JSContext *cx, BaselineInspector *inspector, jsbytecode *pc)
{
if (!b.lhsTypes || !b.rhsTypes)
return;
JS_ASSERT(operandMightEmulateUndefined());
if (!MaybeEmulatesUndefined(b.lhsTypes, cx) && !MaybeEmulatesUndefined(b.rhsTypes, cx))
if (!MaybeEmulatesUndefined(cx, getOperand(0)) && !MaybeEmulatesUndefined(cx, getOperand(1)))
markNoOperandEmulatesUndefined();
MIRType lhs = MIRTypeFromValueType(b.lhsTypes->getKnownTypeTag());
MIRType rhs = MIRTypeFromValueType(b.rhsTypes->getKnownTypeTag());
MIRType lhs = getOperand(0)->type();
MIRType rhs = getOperand(1)->type();
bool looseEq = jsop() == JSOP_EQ || jsop() == JSOP_NE;
bool strictEq = jsop() == JSOP_STRICTEQ || jsop() == JSOP_STRICTNE;
@ -1289,8 +1422,8 @@ MCompare::infer(const TypeOracle::BinaryTypes &b, JSContext *cx)
// Any comparison is allowed except strict eq.
if (!strictEq &&
((lhs == MIRType_Double && SafelyCoercesToDouble(cx, b.rhsTypes)) ||
(rhs == MIRType_Double && SafelyCoercesToDouble(cx, b.lhsTypes))))
((lhs == MIRType_Double && SafelyCoercesToDouble(getOperand(1))) ||
(rhs == MIRType_Double && SafelyCoercesToDouble(getOperand(0)))))
{
compareType_ = Compare_Double;
return;
@ -1352,10 +1485,19 @@ MCompare::infer(const TypeOracle::BinaryTypes &b, JSContext *cx)
}
// Determine if we can do the compare based on a quick value check.
if (!relationalEq && CanDoValueBitwiseCmp(cx, b.lhsTypes, b.rhsTypes, looseEq)) {
if (!relationalEq && CanDoValueBitwiseCmp(cx, getOperand(0), getOperand(1), looseEq)) {
compareType_ = Compare_Value;
return;
}
// Type information is not good enough to pick out a particular type of
// comparison we can do here. Try to specialize based on any baseline
// caches that have been generated for the opcode. These will cause the
// instruction's type policy to insert fallible unboxes to the appropriate
// input types.
if (!strictEq)
compareType_ = inspector->expectedCompareType(pc);
}
MBitNot *
@ -1838,14 +1980,11 @@ MCompare::foldsTo(bool useValueNumbers)
}
void
MNot::infer(const TypeOracle::UnaryTypes &u, JSContext *cx)
MNot::infer(JSContext *cx)
{
if (!u.inTypes)
return;
JS_ASSERT(operandMightEmulateUndefined());
if (!MaybeEmulatesUndefined(u.inTypes, cx))
if (!MaybeEmulatesUndefined(cx, getOperand(0)))
markOperandCantEmulateUndefined();
}
@ -2007,6 +2146,22 @@ InlinePropertyTable::hasFunction(JSFunction *func) const
return false;
}
types::StackTypeSet *
InlinePropertyTable::buildTypeSetForFunction(JSFunction *func) const
{
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
types::StackTypeSet *types = alloc->new_<types::StackTypeSet>();
if (!types)
return NULL;
for (size_t i = 0; i < numEntries(); i++) {
if (entries_[i]->func == func) {
if (!types->addObject(types::Type::ObjectType(entries_[i]->typeObj).objectKey(), alloc))
return NULL;
}
}
return types;
}
bool
MInArray::needsNegativeIntCheck() const
{
@ -2052,3 +2207,375 @@ MAsmJSCall::New(Callee callee, const Args &args, MIRType resultType, size_t spIn
return call;
}
bool
ion::ElementAccessIsDenseNative(MDefinition *obj, MDefinition *id)
{
if (obj->mightBeType(MIRType_String))
return false;
if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
return false;
types::StackTypeSet *types = obj->resultTypeSet();
if (!types)
return false;
Class *clasp = types->getKnownClass();
return clasp && clasp->isNative();
}
bool
ion::ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id, int *arrayType)
{
if (obj->mightBeType(MIRType_String))
return false;
if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
return false;
types::StackTypeSet *types = obj->resultTypeSet();
if (!types)
return false;
*arrayType = types->getTypedArrayType();
return *arrayType != TypedArray::TYPE_MAX;
}
bool
ion::ElementAccessIsPacked(JSContext *cx, MDefinition *obj)
{
types::StackTypeSet *types = obj->resultTypeSet();
return types && !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
}
bool
ion::ElementAccessHasExtraIndexedProperty(JSContext *cx, MDefinition *obj)
{
types::StackTypeSet *types = obj->resultTypeSet();
if (!types || types->hasObjectFlags(cx, types::OBJECT_FLAG_LENGTH_OVERFLOW))
return true;
return types::TypeCanHaveExtraIndexedProperties(cx, types);
}
MIRType
ion::DenseNativeElementType(JSContext *cx, MDefinition *obj)
{
types::StackTypeSet *types = obj->resultTypeSet();
MIRType elementType = MIRType_None;
unsigned count = types->getObjectCount();
for (unsigned i = 0; i < count; i++) {
if (types->getSingleObject(i))
return MIRType_None;
if (types::TypeObject *object = types->getTypeObject(i)) {
if (object->unknownProperties())
return MIRType_None;
types::HeapTypeSet *elementTypes = object->getProperty(cx, JSID_VOID, false);
if (!elementTypes)
return MIRType_None;
MIRType type = MIRTypeFromValueType(elementTypes->getKnownTypeTag(cx));
if (type == MIRType_None)
return MIRType_None;
if (elementType == MIRType_None)
elementType = type;
else if (elementType != type)
return MIRType_None;
}
}
return elementType;
}
bool
ion::PropertyReadNeedsTypeBarrier(JSContext *cx, types::TypeObject *object, PropertyName *name,
types::StackTypeSet *observed)
{
// If the object being read from has types for the property which haven't
// been observed at this access site, the read could produce a new type and
// a barrier is needed. Note that this only covers reads from properties
// which are accounted for by type information, i.e. native data properties
// and elements.
if (object->unknownProperties())
return true;
jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
types::HeapTypeSet *property = object->getProperty(cx, id, false);
if (!property)
return true;
// We need to consider possible types for the property both as an 'own'
// property on the object and as inherited from any prototype. Type sets
// for a property do not, however, reflect inherited types until a
// getFromPrototypes() call has been performed.
if (!property->hasPropagatedProperty())
object->getFromPrototypes(cx, id, property);
if (!TypeSetIncludes(observed, MIRType_Value, property))
return true;
// Type information for global objects does not reflect the initial
// 'undefined' value of variables declared with 'var'. Until the variable
// is assigned a value other than undefined, a barrier is required.
if (property->empty() && name && object->singleton && object->singleton->isNative()) {
Shape *shape = object->singleton->nativeLookup(cx, name);
if (shape && shape->hasDefaultGetter()) {
JS_ASSERT(object->singleton->nativeGetSlot(shape->slot()).isUndefined());
return true;
}
}
property->addFreeze(cx);
return false;
}
bool
ion::PropertyReadNeedsTypeBarrier(JSContext *cx, MDefinition *obj, PropertyName *name,
types::StackTypeSet *observed)
{
if (observed->unknown())
return false;
types::TypeSet *types = obj->resultTypeSet();
if (!types || types->unknownObject())
return true;
for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObject *object = types->getTypeObject(i);
if (!object) {
JSObject *singleton = types->getSingleObject(i);
if (!singleton)
continue;
object = singleton->getType(cx);
if (!object)
return true;
}
if (PropertyReadNeedsTypeBarrier(cx, object, name, observed))
return true;
}
return false;
}
bool
ion::PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *name)
{
// Determine if reading a property from obj is likely to be idempotent.
jsid id = types::IdToTypeId(NameToId(name));
types::TypeSet *types = obj->resultTypeSet();
if (!types || types->unknownObject())
return false;
for (size_t i = 0; i < types->getObjectCount(); i++) {
if (types->getSingleObject(i))
return false;
if (types::TypeObject *object = types->getTypeObject(i)) {
if (object->unknownProperties())
return false;
// Check if the property has been reconfigured or is a getter.
types::HeapTypeSet *property = object->getProperty(cx, id, false);
if (!property || property->isOwnProperty(cx, object, true))
return false;
}
}
return true;
}
static bool
TryAddTypeBarrierForWrite(JSContext *cx, MBasicBlock *current, types::StackTypeSet *objTypes,
jsid id, MDefinition **pvalue)
{
// Return whether pvalue was modified to include a type barrier ensuring
// that writing the value to objTypes/id will not require changing type
// information.
// All objects in the set must have the same types for id. Otherwise, we
// could bail out without subsequently triggering a type change that
// invalidates the compiled code.
types::HeapTypeSet *aggregateProperty = NULL;
for (size_t i = 0; i < objTypes->getObjectCount(); i++) {
types::TypeObject *object = objTypes->getTypeObject(i);
if (!object) {
JSObject *singleton = objTypes->getSingleObject(i);
if (!singleton)
continue;
object = singleton->getType(cx);
if (!object)
return false;
}
if (object->unknownProperties())
return false;
types::HeapTypeSet *property = object->getProperty(cx, id, false);
if (!property)
return false;
if (TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
return false;
// This freeze is not required for correctness, but ensures that we
// will recompile if the property types change and the barrier can
// potentially be removed.
property->addFreeze(cx);
if (aggregateProperty) {
if (!aggregateProperty->isSubset(property) || !property->isSubset(aggregateProperty))
return false;
} else {
aggregateProperty = property;
}
}
JS_ASSERT(aggregateProperty);
MIRType propertyType = MIRTypeFromValueType(aggregateProperty->getKnownTypeTag(cx));
switch (propertyType) {
case MIRType_Boolean:
case MIRType_Int32:
case MIRType_Double:
case MIRType_String: {
// The property is a particular primitive type, guard by unboxing the
// value before the write.
if ((*pvalue)->type() != MIRType_Value) {
// The value is a different primitive, just do a VM call as it will
// always trigger invalidation of the compiled code.
JS_ASSERT((*pvalue)->type() != propertyType);
return false;
}
MInstruction *ins = MUnbox::New(*pvalue, propertyType, MUnbox::Fallible);
current->add(ins);
*pvalue = ins;
return true;
}
default:;
}
if ((*pvalue)->type() != MIRType_Value)
return false;
types::StackTypeSet *types = aggregateProperty->clone(GetIonContext()->temp->lifoAlloc());
if (!types)
return false;
MInstruction *ins = MTypeBarrier::New(*pvalue, types, Bailout_Normal);
current->add(ins);
*pvalue = ins;
return true;
}
static MInstruction *
AddTypeGuard(MBasicBlock *current, MDefinition *obj, types::TypeObject *typeObject,
bool bailOnEquality, BailoutKind bailoutKind)
{
MGuardShapeOrType *guard = MGuardShapeOrType::New(obj, NULL, typeObject,
bailOnEquality, bailoutKind);
current->add(guard);
// For now, never move type guards.
guard->setNotMovable();
return guard;
}
bool
ion::PropertyWriteNeedsTypeBarrier(JSContext *cx, MBasicBlock *current, MDefinition **pobj,
PropertyName *name, MDefinition **pvalue)
{
// If any value being written is not reflected in the type information for
// objects which obj could represent, a type barrier is needed when writing
// the value. As for propertyReadNeedsTypeBarrier, this only applies for
// properties that are accounted for by type information, i.e. normal data
// properties and elements.
types::StackTypeSet *types = (*pobj)->resultTypeSet();
if (!types || types->unknownObject())
return true;
jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
// If all of the objects being written to have property types which already
// reflect the value, no barrier at all is needed. Additionally, if all
// objects being written to have the same types for the property, and those
// types do *not* reflect the value, add a type barrier for the value.
bool success = true;
for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObject *object = types->getTypeObject(i);
if (!object) {
JSObject *singleton = types->getSingleObject(i);
if (!singleton)
continue;
object = singleton->getType(cx);
if (!object) {
success = false;
break;
}
}
if (object->unknownProperties())
continue;
types::HeapTypeSet *property = object->getProperty(cx, id, false);
if (!property) {
success = false;
break;
}
if (!TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet())) {
success = TryAddTypeBarrierForWrite(cx, current, types, id, pvalue);
break;
}
}
if (success)
return false;
// If all of the objects except one have property types which reflect the
// value, and the remaining object has no types at all for the property,
// add a guard that the object does not have that remaining object's type.
if (types->getObjectCount() <= 1)
return true;
types::TypeObject *excluded = NULL;
for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObject *object = types->getTypeObject(i);
if (!object) {
if (types->getSingleObject(i))
return true;
continue;
}
if (object->unknownProperties())
continue;
types::HeapTypeSet *property = object->getProperty(cx, id, false);
if (!property)
return true;
if (TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
continue;
if (!property->empty() || excluded)
return true;
excluded = object;
}
JS_ASSERT(excluded);
*pobj = AddTypeGuard(current, *pobj, excluded, /* bailOnEquality = */ true, Bailout_Normal);
return false;
}

View File

@ -14,7 +14,6 @@
#include "jslibmath.h"
#include "jsinfer.h"
#include "jsinferinlines.h"
#include "TypeOracle.h"
#include "TypePolicy.h"
#include "IonAllocPolicy.h"
#include "InlineList.h"
@ -28,6 +27,7 @@
namespace js {
namespace ion {
class BaselineInspector;
class ValueNumberData;
class Range;
@ -263,6 +263,7 @@ class MDefinition : public MNode
ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use)
Range *range_; // Any computed range for this def.
MIRType resultType_; // Representation of result type.
types::StackTypeSet *resultTypeSet_; // Optional refinement of the result type.
uint32_t flags_; // Bit flags.
union {
MDefinition *dependency_; // Implicit dependency (store, call, etc.) of this instruction.
@ -303,6 +304,7 @@ class MDefinition : public MNode
valueNumber_(NULL),
range_(NULL),
resultType_(MIRType_None),
resultTypeSet_(NULL),
flags_(0),
dependency_(NULL),
trackedPc_(NULL)
@ -392,6 +394,22 @@ class MDefinition : public MNode
return resultType_;
}
types::StackTypeSet *resultTypeSet() const {
return resultTypeSet_;
}
bool mightBeType(MIRType type) const {
JS_ASSERT(type != MIRType_Value);
if (type == this->type())
return true;
if (MIRType_Value != this->type())
return false;
return !resultTypeSet() || resultTypeSet()->mightBeType(ValueTypeFromMIRType(type));
}
// Returns the beginning of this definition's use chain.
MUseIterator usesBegin() const {
return uses_.begin();
@ -469,14 +487,8 @@ class MDefinition : public MNode
void setResultType(MIRType type) {
resultType_ = type;
}
virtual bool acceptsTypeSet() const {
return false;
}
virtual void setTypeSet(const types::StackTypeSet *types) {
}
virtual const types::StackTypeSet *typeSet() const {
return NULL;
void setResultTypeSet(types::StackTypeSet *types) {
resultTypeSet_ = types;
}
MDefinition *dependency() const {
@ -716,28 +728,24 @@ class MConstant : public MNullaryInstruction
class MParameter : public MNullaryInstruction
{
int32_t index_;
const types::StackTypeSet *typeSet_;
public:
static const int32_t THIS_SLOT = -1;
MParameter(int32_t index, const types::StackTypeSet *types)
: index_(index),
typeSet_(types)
MParameter(int32_t index, types::StackTypeSet *types)
: index_(index)
{
setResultType(MIRType_Value);
setResultTypeSet(types);
}
public:
INSTRUCTION_HEADER(Parameter)
static MParameter *New(int32_t index, const types::StackTypeSet *types);
static MParameter *New(int32_t index, types::StackTypeSet *types);
int32_t index() const {
return index_;
}
const types::StackTypeSet *typeSet() const {
return typeSet_;
}
void printOpcode(FILE *fp);
HashNumber valueHash() const;
@ -1000,7 +1008,7 @@ class MTest
AliasSet getAliasSet() const {
return AliasSet::None();
}
void infer(const TypeOracle::UnaryTypes &u, JSContext *cx);
void infer(JSContext *cx);
MDefinition *foldsTo(bool useValueNumbers);
void markOperandCantEmulateUndefined() {
@ -1085,6 +1093,14 @@ class MNewParallelArray : public MNullaryInstruction
}
};
// Fabricate a type set containing only the type of the specified object.
types::StackTypeSet *
MakeSingletonTypeSet(JSObject *obj);
void
MergeTypes(MIRType *ptype, types::StackTypeSet **ptypeSet,
MIRType newType, types::StackTypeSet *newTypeSet);
class MNewArray : public MNullaryInstruction
{
public:
@ -1110,6 +1126,7 @@ class MNewArray : public MNullaryInstruction
allocating_(allocating)
{
setResultType(MIRType_Object);
setResultTypeSet(MakeSingletonTypeSet(templateObject));
}
uint32_t count() const {
@ -1147,6 +1164,7 @@ class MNewObject : public MNullaryInstruction
: templateObject_(templateObject)
{
setResultType(MIRType_Object);
setResultTypeSet(MakeSingletonTypeSet(templateObject));
}
public:
@ -1342,24 +1360,19 @@ class MCall
CompilerRootScript targetScript_;
// Original value of argc from the bytecode.
uint32_t numActualArgs_;
// The typeset of the callee, could be NULL.
types::StackTypeSet *calleeTypes_;
MCall(JSFunction *target, uint32_t numActualArgs, bool construct,
types::StackTypeSet *calleeTypes)
MCall(JSFunction *target, uint32_t numActualArgs, bool construct)
: construct_(construct),
target_(target),
targetScript_(NULL),
numActualArgs_(numActualArgs),
calleeTypes_(calleeTypes)
numActualArgs_(numActualArgs)
{
setResultType(MIRType_Value);
}
public:
INSTRUCTION_HEADER(Call)
static MCall *New(JSFunction *target, size_t maxArgc, size_t numActualArgs, bool construct,
types::StackTypeSet *calleeTypes);
static MCall *New(JSFunction *target, size_t maxArgc, size_t numActualArgs, bool construct);
void initPrepareCall(MDefinition *start) {
JS_ASSERT(start->isPrepareCall());
@ -1401,9 +1414,6 @@ class MCall
bool isConstructing() const {
return construct_;
}
types::StackTypeSet *calleeTypes() const {
return calleeTypes_;
}
// The number of stack arguments is the max between the number of formal
// arguments and the number of actual arguments. The number of stack
@ -1815,7 +1825,7 @@ class MCompare
bool evaluateConstantOperands(bool *result);
MDefinition *foldsTo(bool useValueNumbers);
void infer(const TypeOracle::BinaryTypes &b, JSContext *cx);
void infer(JSContext *cx, BaselineInspector *inspector, jsbytecode *pc);
CompareType compareType() const {
return compareType_;
}
@ -1862,6 +1872,14 @@ class MBox : public MUnaryInstruction
: MUnaryInstruction(ins)
{
setResultType(MIRType_Value);
if (ins->resultTypeSet()) {
setResultTypeSet(ins->resultTypeSet());
} else if (ins->type() != MIRType_Value) {
types::Type ntype = ins->type() == MIRType_Object
? types::Type::AnyObjectType()
: types::Type::PrimitiveType(ValueTypeFromMIRType(ins->type()));
setResultTypeSet(GetIonContext()->temp->lifoAlloc()->new_<types::StackTypeSet>(ntype));
}
setMovable();
}
@ -1896,7 +1914,7 @@ JSOpToCondition(MCompare::CompareType compareType, JSOp op)
// Takes a typed value and checks if it is a certain type. If so, the payload
// is unpacked and returned as that type. Otherwise, it is considered a
// deoptimization.
class MUnbox : public MUnaryInstruction
class MUnbox : public MUnaryInstruction, public BoxInputsPolicy
{
public:
enum Mode {
@ -1921,6 +1939,7 @@ class MUnbox : public MUnaryInstruction
type == MIRType_Object);
setResultType(type);
setResultTypeSet(ins->resultTypeSet());
setMovable();
if (mode_ == TypeBarrier || mode_ == TypeGuard)
@ -1936,6 +1955,10 @@ class MUnbox : public MUnaryInstruction
return new MUnbox(ins, type, mode);
}
TypePolicy *typePolicy() {
return this;
}
Mode mode() const {
return mode_;
}
@ -2033,6 +2056,7 @@ class MCreateThisWithTemplate
: templateObject_(templateObject)
{
setResultType(MIRType_Object);
setResultTypeSet(MakeSingletonTypeSet(templateObject));
}
public:
@ -2168,6 +2192,7 @@ class MPassArg : public MUnaryInstruction
: MUnaryInstruction(def), argnum_(-1)
{
setResultType(def->type());
setResultTypeSet(def->resultTypeSet());
}
public:
@ -2405,7 +2430,7 @@ class MBitNot
}
MDefinition *foldsTo(bool useValueNumbers);
void infer(const TypeOracle::UnaryTypes &u);
void infer();
bool congruentTo(MDefinition *const &ins) const {
return congruentIfOperandsEqual(ins);
@ -2502,7 +2527,7 @@ class MBinaryBitwiseInstruction
virtual MDefinition *foldIfZero(size_t operand) = 0;
virtual MDefinition *foldIfNegOne(size_t operand) = 0;
virtual MDefinition *foldIfEqual() = 0;
virtual void infer(const TypeOracle::BinaryTypes &b);
virtual void infer();
bool congruentTo(MDefinition *const &ins) const {
return congruentIfOperandsEqual(ins);
@ -2598,7 +2623,7 @@ class MShiftInstruction
MDefinition *foldIfEqual() {
return this;
}
virtual void infer(const TypeOracle::BinaryTypes &b);
virtual void infer();
};
class MLsh : public MShiftInstruction
@ -2662,7 +2687,7 @@ class MUrsh : public MShiftInstruction
return this;
}
void infer(const TypeOracle::BinaryTypes &b);
void infer();
bool canOverflow() {
// solution is only negative when lhs < 0 and rhs & 0x1f == 0
@ -2722,7 +2747,7 @@ class MBinaryArithInstruction
virtual double getIdentity() = 0;
void infer(const TypeOracle::BinaryTypes &b, JSContext *cx);
void infer(bool overflowed);
void setInt32() {
specialization_ = MIRType_Int32;
@ -3332,18 +3357,22 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
js::Vector<MUse, 2, IonAllocPolicy> inputs_;
uint32_t slot_;
bool hasBackedgeType_;
bool triedToSpecialize_;
bool isIterator_;
#if DEBUG
bool specialized_;
uint32_t capacity_;
#endif
MPhi(uint32_t slot)
: slot_(slot),
hasBackedgeType_(false),
triedToSpecialize_(false),
isIterator_(false)
#if DEBUG
, specialized_(false)
, capacity_(0)
#endif
{
@ -3360,6 +3389,10 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
static MPhi *New(uint32_t slot);
void setOperand(size_t index, MDefinition *operand) {
// Note: after the initial IonBuilder pass, it is OK to change phi
// operands such that they do not include the type sets of their
// operands. This can arise during e.g. value numbering, where
// definitions producing the same value may have different type sets.
JS_ASSERT(index < numOperands());
inputs_[index].set(operand, this, index);
operand->addUse(&inputs_[index]);
@ -3376,6 +3409,9 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
uint32_t slot() const {
return slot_;
}
bool hasBackedgeType() const {
return hasBackedgeType_;
}
bool triedToSpecialize() const {
return triedToSpecialize_;
}
@ -3383,6 +3419,14 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
triedToSpecialize_ = true;
setResultType(type);
}
void specializeType();
// Whether this phi's type already includes information for def.
bool typeIncludes(MDefinition *def);
// Add types for this phi which speculate about new inputs that may come in
// via a loop backedge.
void addBackedgeType(MIRType type, types::StackTypeSet *typeSet);
// Initializes the operands vector to the given capacity,
// permitting use of addInput() instead of addInputSlow().
@ -3393,7 +3437,7 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
// Appends a new input to the input vector. May call realloc().
// Prefer reserveLength() and addInput() instead, where possible.
bool addInputSlow(MDefinition *ins);
bool addInputSlow(MDefinition *ins, bool *ptypeChange = NULL);
MDefinition *foldsTo(bool useValueNumbers);
@ -3437,6 +3481,7 @@ class MBeta : public MUnaryInstruction
val_(val)
{
setResultType(val->type());
setResultTypeSet(val->resultTypeSet());
}
public:
@ -3641,6 +3686,9 @@ class MRegExp : public MNullaryInstruction
prototype_(prototype)
{
setResultType(MIRType_Object);
JS_ASSERT(source->getProto() == prototype);
setResultTypeSet(MakeSingletonTypeSet(source));
}
public:
@ -4110,7 +4158,7 @@ class MNot
INSTRUCTION_HEADER(Not);
void infer(const TypeOracle::UnaryTypes &u, JSContext *cx);
void infer(JSContext *cx);
MDefinition *foldsTo(bool useValueNumbers);
void markOperandCantEmulateUndefined() {
@ -4861,11 +4909,10 @@ class MLoadFixedSlot
public SingleObjectPolicy
{
size_t slot_;
const types::StackTypeSet *types_;
protected:
MLoadFixedSlot(MDefinition *obj, size_t slot)
: MUnaryInstruction(obj), slot_(slot), types_(NULL)
: MUnaryInstruction(obj), slot_(slot)
{
setResultType(MIRType_Value);
setMovable();
@ -4882,16 +4929,6 @@ class MLoadFixedSlot
return this;
}
virtual bool acceptsTypeSet() const {
return true;
}
virtual void setTypeSet(const types::StackTypeSet *types) {
types_ = types;
}
virtual const types::StackTypeSet *typeSet() const {
return types_;
}
MDefinition *object() const {
return getOperand(0);
}
@ -5013,6 +5050,7 @@ class InlinePropertyTable : public TempObject
}
bool hasFunction(JSFunction *func) const;
types::StackTypeSet *buildTypeSetForFunction(JSFunction *func) const;
// Remove targets that vetoed inlining from the InlinePropertyTable.
void trimTo(AutoObjectVector &targets, Vector<bool> &choiceSet);
@ -5487,29 +5525,37 @@ class MBindNameCache
}
};
// Guard on an object's shape.
class MGuardShape
// Guard on an object's shape or type, either inclusively or exclusively.
class MGuardShapeOrType
: public MUnaryInstruction,
public SingleObjectPolicy
{
CompilerRootShape shape_;
CompilerRoot<types::TypeObject*> typeObject_;
bool bailOnEquality_;
BailoutKind bailoutKind_;
MGuardShape(MDefinition *obj, RawShape shape, BailoutKind bailoutKind)
MGuardShapeOrType(MDefinition *obj, Shape *shape, types::TypeObject *typeObject,
bool bailOnEquality, BailoutKind bailoutKind)
: MUnaryInstruction(obj),
shape_(shape),
typeObject_(typeObject),
bailOnEquality_(bailOnEquality),
bailoutKind_(bailoutKind)
{
// Exactly one of the shape or type object to guard on must be specified.
JS_ASSERT(!!shape != !!typeObject);
setGuard();
setMovable();
setResultType(MIRType_Object);
}
public:
INSTRUCTION_HEADER(GuardShape)
INSTRUCTION_HEADER(GuardShapeOrType)
static MGuardShape *New(MDefinition *obj, RawShape shape, BailoutKind bailoutKind) {
return new MGuardShape(obj, shape, bailoutKind);
static MGuardShapeOrType *New(MDefinition *obj, Shape *shape, types::TypeObject *typeObject,
bool bailOnEquality, BailoutKind bailoutKind) {
return new MGuardShapeOrType(obj, shape, typeObject, bailOnEquality, bailoutKind);
}
TypePolicy *typePolicy() {
@ -5521,15 +5567,25 @@ class MGuardShape
const RawShape shape() const {
return shape_;
}
types::TypeObject *typeObject() const {
return typeObject_;
}
bool bailOnEquality() const {
return bailOnEquality_;
}
BailoutKind bailoutKind() const {
return bailoutKind_;
}
bool congruentTo(MDefinition * const &ins) const {
if (!ins->isGuardShape())
if (!ins->isGuardShapeOrType())
return false;
if (shape() != ins->toGuardShape()->shape())
if (shape() != ins->toGuardShapeOrType()->shape())
return false;
if (bailoutKind() != ins->toGuardShape()->bailoutKind())
if (typeObject() != ins->toGuardShapeOrType()->typeObject())
return false;
if (bailOnEquality() != ins->toGuardShapeOrType()->bailOnEquality())
return false;
if (bailoutKind() != ins->toGuardShapeOrType()->bailoutKind())
return false;
return congruentIfOperandsEqual(ins);
}
@ -5587,12 +5643,10 @@ class MLoadSlot
public SingleObjectPolicy
{
uint32_t slot_;
const types::StackTypeSet *types_;
MLoadSlot(MDefinition *slots, uint32_t slot)
: MUnaryInstruction(slots),
slot_(slot),
types_(NULL)
slot_(slot)
{
setResultType(MIRType_Value);
setMovable();
@ -5616,16 +5670,6 @@ class MLoadSlot
return slot_;
}
virtual bool acceptsTypeSet() const {
return true;
}
virtual void setTypeSet(const types::StackTypeSet *types) {
types_ = types;
}
virtual const types::StackTypeSet *typeSet() const {
return types_;
}
bool congruentTo(MDefinition * const &ins) const {
if (!ins->isLoadSlot())
return false;
@ -6049,6 +6093,44 @@ class MCallSetElement
}
};
class MCallInitElementArray
: public MAryInstruction<2>,
public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
{
uint32_t index_;
MCallInitElementArray(MDefinition *obj, uint32_t index, MDefinition *val)
: index_(index)
{
setOperand(0, obj);
setOperand(1, val);
}
public:
INSTRUCTION_HEADER(CallInitElementArray)
static MCallInitElementArray *New(MDefinition *obj, uint32_t index, MDefinition *val)
{
return new MCallInitElementArray(obj, index, val);
}
MDefinition *object() const {
return getOperand(0);
}
uint32_t index() const {
return index_;
}
MDefinition *value() const {
return getOperand(1);
}
TypePolicy *typePolicy() {
return this;
}
};
class MSetDOMProperty
: public MAryInstruction<2>,
public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
@ -6603,13 +6685,13 @@ class MTypeBarrier
public BoxInputsPolicy
{
BailoutKind bailoutKind_;
const types::StackTypeSet *typeSet_;
MTypeBarrier(MDefinition *def, const types::StackTypeSet *types, BailoutKind bailoutKind)
: MUnaryInstruction(def),
typeSet_(types)
MTypeBarrier(MDefinition *def, types::StackTypeSet *types, BailoutKind bailoutKind)
: MUnaryInstruction(def)
{
JS_ASSERT(!types->unknown());
setResultType(MIRType_Value);
setResultTypeSet(types);
setGuard();
setMovable();
bailoutKind_ = bailoutKind;
@ -6618,13 +6700,13 @@ class MTypeBarrier
public:
INSTRUCTION_HEADER(TypeBarrier)
static MTypeBarrier *New(MDefinition *def, const types::StackTypeSet *types) {
static MTypeBarrier *New(MDefinition *def, types::StackTypeSet *types) {
BailoutKind bailoutKind = def->isEffectful()
? Bailout_TypeBarrier
: Bailout_Normal;
return new MTypeBarrier(def, types, bailoutKind);
}
static MTypeBarrier *New(MDefinition *def, const types::StackTypeSet *types,
static MTypeBarrier *New(MDefinition *def, types::StackTypeSet *types,
BailoutKind bailoutKind) {
return new MTypeBarrier(def, types, bailoutKind);
}
@ -6642,14 +6724,11 @@ class MTypeBarrier
BailoutKind bailoutKind() const {
return bailoutKind_;
}
const types::StackTypeSet *typeSet() const {
return typeSet_;
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
virtual bool neverHoist() const {
return typeSet()->empty();
return resultTypeSet()->empty();
}
};
@ -7477,6 +7556,21 @@ static inline bool isOSRLikeValue (MDefinition *def) {
typedef Vector<MDefinition *, 8, IonAllocPolicy> MDefinitionVector;
// Helper functions used to decide how to build MIR.
bool ElementAccessIsDenseNative(MDefinition *obj, MDefinition *id);
bool ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id, int *arrayType);
bool ElementAccessIsPacked(JSContext *cx, MDefinition *obj);
bool ElementAccessHasExtraIndexedProperty(JSContext *cx, MDefinition *obj);
MIRType DenseNativeElementType(JSContext *cx, MDefinition *obj);
bool PropertyReadNeedsTypeBarrier(JSContext *cx, types::TypeObject *object, PropertyName *name,
types::StackTypeSet *observed);
bool PropertyReadNeedsTypeBarrier(JSContext *cx, MDefinition *obj, PropertyName *name,
types::StackTypeSet *observed);
bool PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *name);
bool PropertyWriteNeedsTypeBarrier(JSContext *cx, MBasicBlock *current, MDefinition **pobj,
PropertyName *name, MDefinition **pvalue);
} // namespace ion
} // namespace js

View File

@ -62,6 +62,27 @@ MIRGraph::insertBlockAfter(MBasicBlock *at, MBasicBlock *block)
numBlocks_++;
}
void
MIRGraph::removeBlocksAfter(MBasicBlock *start)
{
MBasicBlockIterator iter(begin());
iter++;
while (iter != end()) {
MBasicBlock *block = *iter;
iter++;
if (block->id() <= start->id())
continue;
if (block == osrBlock_)
osrBlock_ = NULL;
block->discardAllInstructions();
block->discardAllPhis();
block->markAsDead();
removeBlock(block);
}
}
void
MIRGraph::unmarkBlocks() {
for (MBasicBlockIterator i(blocks_.begin()); i != blocks_.end(); i++)
@ -350,10 +371,12 @@ MBasicBlock::linkOsrValues(MStart *start)
for (uint32_t i = 0; i < stackDepth(); i++) {
MDefinition *def = slots_[i];
if (i == info().scopeChainSlot())
def->toOsrScopeChain()->setResumePoint(res);
else
if (i == info().scopeChainSlot()) {
if (def->isOsrScopeChain())
def->toOsrScopeChain()->setResumePoint(res);
} else {
def->toOsrValue()->setResumePoint(res);
}
}
}
@ -576,6 +599,31 @@ MBasicBlock::discardDefAt(MDefinitionIterator &old)
return iter;
}
void
MBasicBlock::discardAllInstructions()
{
for (MInstructionIterator iter = begin(); iter != end(); ) {
for (size_t i = 0; i < iter->numOperands(); i++)
iter->discardOperand(i);
iter = instructions_.removeAt(iter);
}
lastIns_ = NULL;
}
void
MBasicBlock::discardAllPhis()
{
for (MPhiIterator iter = phisBegin(); iter != phisEnd(); ) {
MPhi *phi = *iter;
for (size_t i = 0; i < phi->numOperands(); i++)
phi->discardOperand(i);
iter = phis_.removeAt(iter);
}
for (MBasicBlock **pred = predecessors_.begin(); pred != predecessors_.end(); pred++)
(*pred)->setSuccessorWithPhis(NULL, 0);
}
void
MBasicBlock::insertBefore(MInstruction *at, MInstruction *ins)
{
@ -725,7 +773,7 @@ MBasicBlock::dominates(MBasicBlock *other)
return other->domIndex() >= low && other->domIndex() <= high;
}
bool
AbortReason
MBasicBlock::setBackedge(MBasicBlock *pred)
{
// Predecessors must be finished, and at the correct stack depth.
@ -736,6 +784,8 @@ MBasicBlock::setBackedge(MBasicBlock *pred)
// We must be a pending loop header
JS_ASSERT(kind_ == PENDING_LOOP_HEADER);
bool hadTypeChange = false;
// Add exit definitions to each corresponding phi at the entry.
for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++) {
MPhi *entryDef = *phi;
@ -755,17 +805,30 @@ MBasicBlock::setBackedge(MBasicBlock *pred)
exitDef = entryDef->getOperand(0);
}
if (!entryDef->addInputSlow(exitDef))
return false;
bool typeChange = false;
if (!entryDef->addInputSlow(exitDef, &typeChange))
return AbortReason_Alloc;
hadTypeChange |= typeChange;
JS_ASSERT(entryDef->slot() < pred->stackDepth());
setSlot(entryDef->slot(), entryDef);
}
if (hadTypeChange) {
for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++)
phi->removeOperand(phi->numOperands() - 1);
return AbortReason_Disable;
}
// We are now a loop header proper
kind_ = LOOP_HEADER;
return predecessors_.append(pred);
if (!predecessors_.append(pred))
return AbortReason_Alloc;
return AbortReason_NoAbort;
}
void
@ -890,6 +953,15 @@ MBasicBlock::inheritPhis(MBasicBlock *header)
}
}
void
MBasicBlock::specializePhis()
{
for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++) {
MPhi *phi = *iter;
phi->specializeType();
}
}
void
MBasicBlock::dumpStack(FILE *fp)
{

View File

@ -36,7 +36,8 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
NORMAL,
PENDING_LOOP_HEADER,
LOOP_HEADER,
SPLIT_EDGE
SPLIT_EDGE,
DEAD
};
private:
@ -183,8 +184,9 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
void clearDominatorInfo();
// Sets a back edge. This places phi nodes and rewrites instructions within
// the current loop as necessary.
bool setBackedge(MBasicBlock *block);
// the current loop as necessary. If the backedge introduces new types for
// phis at the loop header, returns a disabling abort.
AbortReason setBackedge(MBasicBlock *block);
// Resets a LOOP_HEADER block to a NORMAL block. This is needed when
// optimizations remove the backedge.
@ -193,6 +195,9 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
// Propagates phis placed in a loop header down to this successor block.
void inheritPhis(MBasicBlock *header);
// Compute the types for phis in this block according to their inputs.
void specializePhis();
void insertBefore(MInstruction *at, MInstruction *ins);
void insertAfter(MInstruction *at, MInstruction *ins);
@ -208,10 +213,17 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
MInstructionIterator discardAt(MInstructionIterator &iter);
MInstructionReverseIterator discardAt(MInstructionReverseIterator &iter);
MDefinitionIterator discardDefAt(MDefinitionIterator &iter);
void discardAllInstructions();
void discardAllPhis();
// Discards a phi instruction and updates predecessor successorWithPhis.
MPhiIterator discardPhiAt(MPhiIterator &at);
// Mark this block as having been removed from the graph.
void markAsDead() {
kind_ = DEAD;
}
///////////////////////////////////////////////////////
/////////// END GRAPH BUILDING INSTRUCTIONS ///////////
///////////////////////////////////////////////////////
@ -302,6 +314,9 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
bool isSplitEdge() const {
return kind_ == SPLIT_EDGE;
}
bool isDead() const {
return kind_ == DEAD;
}
uint32_t stackDepth() const {
return stackPosition_;
@ -554,6 +569,7 @@ class MIRGraph
ReversePostorderIterator rpoEnd() {
return blocks_.end();
}
void removeBlocksAfter(MBasicBlock *block);
void removeBlock(MBasicBlock *block) {
blocks_.remove(block);
numBlocks_--;

View File

@ -102,7 +102,7 @@ namespace ion {
_(GetPropertyCache) \
_(GetElementCache) \
_(BindNameCache) \
_(GuardShape) \
_(GuardShapeOrType) \
_(GuardClass) \
_(ArrayLength) \
_(TypedArrayLength) \
@ -135,6 +135,7 @@ namespace ion {
_(CallGetElement) \
_(CallSetElement) \
_(CallSetProperty) \
_(CallInitElementArray) \
_(DeleteProperty) \
_(SetPropertyCache) \
_(IteratorStart) \

View File

@ -191,7 +191,7 @@ class ParallelArrayVisitor : public MInstructionVisitor
SAFE_OP(GetPropertyCache)
UNSAFE_OP(GetElementCache)
UNSAFE_OP(BindNameCache)
SAFE_OP(GuardShape)
SAFE_OP(GuardShapeOrType)
SAFE_OP(GuardClass)
SAFE_OP(ArrayLength)
SAFE_OP(TypedArrayLength)
@ -220,6 +220,7 @@ class ParallelArrayVisitor : public MInstructionVisitor
UNSAFE_OP(CallsiteCloneCache)
UNSAFE_OP(CallGetElement)
UNSAFE_OP(CallSetElement)
UNSAFE_OP(CallInitElementArray)
UNSAFE_OP(CallSetProperty)
UNSAFE_OP(DeleteProperty)
UNSAFE_OP(SetPropertyCache)
@ -725,9 +726,7 @@ static bool
GetPossibleCallees(JSContext *cx, HandleScript script, jsbytecode *pc,
types::StackTypeSet *calleeTypes, MIRGraph &graph)
{
JS_ASSERT(calleeTypes);
if (calleeTypes->baseFlags() != 0)
if (!calleeTypes || calleeTypes->baseFlags() != 0)
return true;
unsigned objCount = calleeTypes->getObjectCount();
@ -768,8 +767,6 @@ GetPossibleCallees(JSContext *cx, HandleScript script, jsbytecode *pc,
bool
ParallelArrayVisitor::visitCall(MCall *ins)
{
JS_ASSERT(ins->getSingleTarget() || ins->calleeTypes());
// DOM? Scary.
if (ins->isDOMFunction()) {
SpewMIR(ins, "call to dom function");
@ -791,9 +788,11 @@ ParallelArrayVisitor::visitCall(MCall *ins)
return markUnsafe();
}
types::StackTypeSet *calleeTypes = ins->getFunction()->resultTypeSet();
RootedScript script(cx_, ins->block()->info().script());
return GetPossibleCallees(cx_, script, ins->resumePoint()->pc(),
ins->calleeTypes(), graph_);
calleeTypes, graph_);
}
/////////////////////////////////////////////////////////////////////////////

View File

@ -222,10 +222,34 @@ ion::ParallelAbort(JSScript *script)
void
ion::ParCallToUncompiledScript(JSFunction *func)
{
static const int max_bound_function_unrolling = 5;
JS_ASSERT(InParallelSection());
#ifdef DEBUG
RawScript script = func->nonLazyScript();
Spew(SpewBailouts, "Call to uncompiled script: %p:%s:%d", script, script->filename(), script->lineno);
if (func->hasScript()) {
JSScript *script = func->nonLazyScript();
Spew(SpewBailouts, "Call to uncompiled script: %p:%s:%d",
script, script->filename(), script->lineno);
} else if (func->isBoundFunction()) {
int depth = 0;
JSFunction *target = func->getBoundFunctionTarget()->toFunction();
while (depth < max_bound_function_unrolling) {
if (target->hasScript())
break;
if (target->isBoundFunction())
target = target->getBoundFunctionTarget()->toFunction();
depth--;
}
if (target->hasScript()) {
JSScript *script = target->nonLazyScript();
Spew(SpewBailouts, "Call to bound function leading (depth: %d) to script: %p:%s:%d",
depth, script, script->filename(), script->lineno);
} else {
Spew(SpewBailouts, "Call to bound function (excessive depth: %d)", depth);
}
} else {
JS_NOT_REACHED("ParCall'ed functions must have scripts or be ES6 bound functions.");
}
#endif
}

View File

@ -8,7 +8,6 @@
#define jsion_cpu_registersets_h__
#include "Registers.h"
#include "TypeOracle.h"
#include "ion/IonAllocPolicy.h"
namespace js {

View File

@ -1,894 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TypeOracle.h"
#include "Ion.h"
#include "IonSpewer.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "jsanalyze.h"
using namespace js;
using namespace js::ion;
using namespace js::types;
using namespace js::analyze;
TypeInferenceOracle::TypeInferenceOracle()
: cx(NULL),
script_(NULL)
{}
bool
TypeInferenceOracle::init(JSContext *cx, JSScript *script, bool inlinedCall)
{
AutoEnterAnalysis enter(cx);
this->cx = cx;
this->script_.init(script);
if (inlinedCall) {
JS_ASSERT_IF(script->length != 1, script->analysis()->ranInference());
return script->ensureRanInference(cx);
}
Vector<JSScript*> seen(cx);
return analyzeTypesForInlinableCallees(cx, script, seen);
}
bool
TypeInferenceOracle::analyzeTypesForInlinableCallees(JSContext *cx, JSScript *script,
Vector<JSScript*> &seen)
{
// Don't analyze scripts which will not be inlined (but always analyze the first script).
if (seen.length() > 0 && script->getUseCount() < js_IonOptions.usesBeforeInlining())
return true;
for (size_t i = 0; i < seen.length(); i++) {
if (seen[i] == script)
return true;
}
if (!seen.append(script))
return false;
if (!script->ensureRanInference(cx))
return false;
ScriptAnalysis *analysis = script->analysis();
JS_ASSERT(analysis->ranInference());
for (jsbytecode *pc = script->code;
pc < script->code + script->length;
pc += GetBytecodeLength(pc))
{
if (!(js_CodeSpec[*pc].format & JOF_INVOKE))
continue;
if (!analysis->maybeCode(pc))
continue;
uint32_t argc = GET_ARGC(pc);
StackTypeSet *calleeTypes = analysis->poppedTypes(pc, argc + 1);
if (!analyzeTypesForInlinableCallees(cx, calleeTypes, seen))
return false;
// For foo.call() and foo.apply(), also look for any callees in the
// 'this' types of the call, which might be inlined by Ion.
if (*pc == JSOP_FUNCALL || *pc == JSOP_FUNAPPLY) {
StackTypeSet *thisTypes = analysis->poppedTypes(pc, argc);
if (!analyzeTypesForInlinableCallees(cx, thisTypes, seen))
return false;
}
}
return true;
}
bool
TypeInferenceOracle::analyzeTypesForInlinableCallees(JSContext *cx, StackTypeSet *calleeTypes,
Vector<JSScript*> &seen)
{
if (calleeTypes->unknownObject())
return true;
size_t count = calleeTypes->getObjectCount();
for (size_t i = 0; i < count; i++) {
JSScript *script;
if (JSObject *singleton = calleeTypes->getSingleObject(i)) {
if (!singleton->isFunction() || !singleton->toFunction()->hasScript())
continue;
script = singleton->toFunction()->nonLazyScript();
} else if (TypeObject *type = calleeTypes->getTypeObject(i)) {
JSFunction *fun = type->interpretedFunction;
if (!fun || !fun->hasScript())
continue;
script = fun->nonLazyScript();
} else {
continue;
}
if (!analyzeTypesForInlinableCallees(cx, script, seen))
return false;
// The contents of type sets can change after analyzing the types in a
// script. Make a sanity check to ensure the set is ok to keep using.
if (calleeTypes->unknownObject() || calleeTypes->getObjectCount() != count)
break;
}
return true;
}
MIRType
GetMIRType(JSValueType type)
{
/* Get the suggested representation to use for values in a given type set. */
switch (type) {
case JSVAL_TYPE_UNDEFINED:
return MIRType_Undefined;
case JSVAL_TYPE_NULL:
return MIRType_Null;
case JSVAL_TYPE_BOOLEAN:
return MIRType_Boolean;
case JSVAL_TYPE_INT32:
return MIRType_Int32;
case JSVAL_TYPE_DOUBLE:
return MIRType_Double;
case JSVAL_TYPE_STRING:
return MIRType_String;
case JSVAL_TYPE_OBJECT:
return MIRType_Object;
case JSVAL_TYPE_MAGIC:
return MIRType_Magic;
default:
return MIRType_Value;
}
}
MIRType
TypeInferenceOracle::getMIRType(StackTypeSet *types)
{
return GetMIRType(types->getKnownTypeTag());
}
MIRType
TypeInferenceOracle::getMIRType(HeapTypeSet *types)
{
return GetMIRType(types->getKnownTypeTag(cx));
}
TypeOracle::UnaryTypes
TypeInferenceOracle::unaryTypes(RawScript script, jsbytecode *pc)
{
JS_ASSERT(script == this->script());
UnaryTypes res;
res.inTypes = script->analysis()->poppedTypes(pc, 0);
res.outTypes = script->analysis()->pushedTypes(pc, 0);
return res;
}
TypeOracle::BinaryTypes
TypeInferenceOracle::binaryTypes(RawScript script, jsbytecode *pc)
{
JS_ASSERT(script == this->script());
JSOp op = (JSOp)*pc;
BinaryTypes res;
if (op == JSOP_NEG || op == JSOP_POS) {
res.lhsTypes = script->analysis()->poppedTypes(pc, 0);
res.rhsTypes = NULL;
res.outTypes = script->analysis()->pushedTypes(pc, 0);
} else {
res.lhsTypes = script->analysis()->poppedTypes(pc, 1);
res.rhsTypes = script->analysis()->poppedTypes(pc, 0);
res.outTypes = script->analysis()->pushedTypes(pc, 0);
}
return res;
}
TypeOracle::Unary
TypeInferenceOracle::unaryOp(RawScript script, jsbytecode *pc)
{
JS_ASSERT(script == this->script());
Unary res;
res.ival = getMIRType(script->analysis()->poppedTypes(pc, 0));
res.rval = getMIRType(script->analysis()->pushedTypes(pc, 0));
return res;
}
TypeOracle::Binary
TypeInferenceOracle::binaryOp(RawScript script, jsbytecode *pc)
{
JS_ASSERT(script == this->script());
JSOp op = (JSOp)*pc;
Binary res;
if (op == JSOP_NEG || op == JSOP_POS) {
res.lhs = getMIRType(script->analysis()->poppedTypes(pc, 0));
res.rhs = MIRType_Int32;
res.rval = getMIRType(script->analysis()->pushedTypes(pc, 0));
} else {
res.lhs = getMIRType(script->analysis()->poppedTypes(pc, 1));
res.rhs = getMIRType(script->analysis()->poppedTypes(pc, 0));
res.rval = getMIRType(script->analysis()->pushedTypes(pc, 0));
}
return res;
}
StackTypeSet *
TypeInferenceOracle::thisTypeSet(RawScript script)
{
JS_ASSERT(script == this->script());
return TypeScript::ThisTypes(script);
}
bool
TypeInferenceOracle::getOsrTypes(jsbytecode *osrPc, Vector<MIRType> &slotTypes)
{
JS_ASSERT(JSOp(*osrPc) == JSOP_LOOPENTRY);
JS_ASSERT(script()->code < osrPc);
JS_ASSERT(osrPc < script()->code + script()->length);
Vector<types::StackTypeSet *> slotTypeSets(cx);
if (!slotTypeSets.resize(TotalSlots(script())))
return false;
for (uint32_t slot = ThisSlot(); slot < TotalSlots(script()); slot++)
slotTypeSets[slot] = TypeScript::SlotTypes(script(), slot);
jsbytecode *pc = script()->code;
ScriptAnalysis *analysis = script()->analysis();
// To determine the slot types at the OSR pc, we have to do a forward walk
// over the bytecode to reconstruct the types.
for (;;) {
Bytecode *opinfo = analysis->maybeCode(pc);
if (opinfo) {
if (opinfo->jumpTarget) {
// Update variable types for all new values at this bytecode.
if (const SlotValue *newv = analysis->newValues(pc)) {
while (newv->slot) {
if (newv->slot < TotalSlots(script()))
slotTypeSets[newv->slot] = analysis->getValueTypes(newv->value);
newv++;
}
}
}
if (BytecodeUpdatesSlot(JSOp(*pc))) {
uint32_t slot = GetBytecodeSlot(script(), pc);
if (analysis->trackSlot(slot))
slotTypeSets[slot] = analysis->pushedTypes(pc, 0);
}
}
if (pc == osrPc)
break;
pc += GetBytecodeLength(pc);
}
JS_ASSERT(pc == osrPc);
// TI always includes the |this| slot, but Ion only does so for function
// scripts. This means we have to subtract 1 for global/eval scripts.
JS_ASSERT(ThisSlot() == 1);
JS_ASSERT(ArgSlot(0) == 2);
#ifdef DEBUG
uint32_t stackDepth = analysis->getCode(osrPc).stackDepth;
#endif
if (script()->function()) {
JS_ASSERT(slotTypes.length() == TotalSlots(script()) + stackDepth);
for (size_t i = ThisSlot(); i < TotalSlots(script()); i++)
slotTypes[i] = getMIRType(slotTypeSets[i]);
} else {
JS_ASSERT(slotTypes.length() == TotalSlots(script()) + stackDepth - 1);
for (size_t i = ArgSlot(0); i < TotalSlots(script()); i++)
slotTypes[i - 1] = getMIRType(slotTypeSets[i]);
}
return true;
}
StackTypeSet *
TypeInferenceOracle::parameterTypeSet(RawScript script, size_t index)
{
JS_ASSERT(script == this->script());
return TypeScript::ArgTypes(script, index);
}
StackTypeSet *
TypeInferenceOracle::propertyRead(RawScript script, jsbytecode *pc)
{
return script->analysis()->pushedTypes(pc, 0);
}
StackTypeSet *
TypeInferenceOracle::propertyReadBarrier(HandleScript script, jsbytecode *pc)
{
if (script->analysis()->typeBarriers(cx, pc))
return script->analysis()->bytecodeTypes(pc);
return NULL;
}
bool
TypeInferenceOracle::propertyReadIdempotent(HandleScript script, jsbytecode *pc, HandleId id)
{
if (id != IdToTypeId(id))
return false;
StackTypeSet *types = script->analysis()->poppedTypes(pc, 0);
if (!types || types->unknownObject())
return false;
for (unsigned i = 0; i < types->getObjectCount(); i++) {
if (types->getSingleObject(i))
return false;
if (TypeObject *obj = types->getTypeObject(i)) {
if (obj->unknownProperties())
return false;
// Check if the property has been reconfigured or is a getter.
HeapTypeSet *propertyTypes = obj->getProperty(cx, id, false);
if (!propertyTypes || propertyTypes->isOwnProperty(cx, obj, true))
return false;
}
}
return true;
}
bool
TypeInferenceOracle::propertyReadAccessGetter(RawScript script, jsbytecode *pc)
{
return script->analysis()->getCode(pc).accessGetter;
}
bool
TypeInferenceOracle::inObjectIsDenseNativeWithoutExtraIndexedProperties(HandleScript script, jsbytecode *pc)
{
// Check whether the object is a native and index is int32 or double.
StackTypeSet *id = script->analysis()->poppedTypes(pc, 1);
StackTypeSet *obj = script->analysis()->poppedTypes(pc, 0);
JSValueType idType = id->getKnownTypeTag();
if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE)
return false;
Class *clasp = obj->getKnownClass();
if (!clasp || !clasp->isNative())
return false;
return !types::TypeCanHaveExtraIndexedProperties(cx, obj);
}
bool
TypeInferenceOracle::inArrayIsPacked(RawScript script, jsbytecode *pc)
{
StackTypeSet *types = script->analysis()->poppedTypes(pc, 0);
return !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
}
bool
TypeInferenceOracle::elementReadIsDenseNative(RawScript script, jsbytecode *pc)
{
// Check whether the object is a dense array and index is int32 or double.
StackTypeSet *obj = script->analysis()->poppedTypes(pc, 1);
StackTypeSet *id = script->analysis()->poppedTypes(pc, 0);
JSValueType idType = id->getKnownTypeTag();
if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE)
return false;
if (obj->hasType(types::Type::StringType()))
return false;
Class *clasp = obj->getKnownClass();
return clasp && clasp->isNative();
}
bool
TypeInferenceOracle::elementReadIsTypedArray(RawScript script, jsbytecode *pc, int *arrayType)
{
// Check whether the object is a typed array and index is int32 or double.
StackTypeSet *obj = script->analysis()->poppedTypes(pc, 1);
StackTypeSet *id = script->analysis()->poppedTypes(pc, 0);
JSValueType idType = id->getKnownTypeTag();
if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE)
return false;
if (obj->hasType(types::Type::StringType()))
return false;
*arrayType = obj->getTypedArrayType();
if (*arrayType == TypedArray::TYPE_MAX)
return false;
JS_ASSERT(*arrayType >= 0 && *arrayType < TypedArray::TYPE_MAX);
// Unlike dense arrays, the types of elements in typed arrays are not
// guaranteed to be present in the object's type, and we need to use
// knowledge about the possible contents of the array vs. the types
// that have been read out of it to figure out how to do the load.
types::TypeSet *result = propertyRead(script, pc);
if (*arrayType == TypedArray::TYPE_FLOAT32 || *arrayType == TypedArray::TYPE_FLOAT64) {
if (!result->hasType(types::Type::DoubleType()))
return false;
} else {
if (!result->hasType(types::Type::Int32Type()))
return false;
}
return true;
}
bool
TypeInferenceOracle::elementReadIsString(RawScript script, jsbytecode *pc)
{
// Check for string[index].
StackTypeSet *value = script->analysis()->poppedTypes(pc, 1);
StackTypeSet *id = script->analysis()->poppedTypes(pc, 0);
if (value->getKnownTypeTag() != JSVAL_TYPE_STRING)
return false;
JSValueType idType = id->getKnownTypeTag();
if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE)
return false;
// This function is used for jsop_getelem_string which should return
// undefined if this is out-side the string bounds. Currently we just
// fallback to a CallGetElement.
StackTypeSet *pushed = script->analysis()->pushedTypes(pc, 0);
if (pushed->getKnownTypeTag() != JSVAL_TYPE_STRING)
return false;
return true;
}
bool
TypeInferenceOracle::elementReadShouldAlwaysLoadDoubles(RawScript script, jsbytecode *pc)
{
StackTypeSet *types = script->analysis()->poppedTypes(pc, 1);
types::StackTypeSet::DoubleConversion conversion = types->convertDoubleElements(cx);
return conversion == StackTypeSet::AlwaysConvertToDoubles;
}
bool
TypeInferenceOracle::elementReadHasExtraIndexedProperty(RawScript script, jsbytecode *pc)
{
StackTypeSet *obj = script->analysis()->poppedTypes(pc, 1);
return types::TypeCanHaveExtraIndexedProperties(cx, obj);
}
bool
TypeInferenceOracle::elementReadIsPacked(RawScript script, jsbytecode *pc)
{
StackTypeSet *types = script->analysis()->poppedTypes(pc, 1);
return !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
}
void
TypeInferenceOracle::elementReadGeneric(RawScript script, jsbytecode *pc, bool *cacheable, bool *monitorResult, bool *intIndex)
{
MIRType obj = getMIRType(script->analysis()->poppedTypes(pc, 1));
MIRType id = getMIRType(script->analysis()->poppedTypes(pc, 0));
*cacheable = (obj == MIRType_Object &&
(id == MIRType_Value || id == MIRType_Int32 || id == MIRType_String));
*intIndex = id == MIRType_Int32;
// Turn off cacheing if the element is int32 and we've seen non-native objects as the target
// of this getelem.
if (*cacheable && id == MIRType_Int32 && script->analysis()->getCode(pc).nonNativeGetElement)
*cacheable = false;
if (*cacheable)
*monitorResult = (id == MIRType_String || script->analysis()->getCode(pc).getStringElement);
else
*monitorResult = true;
}
bool
TypeInferenceOracle::elementWriteIsDenseNative(HandleScript script, jsbytecode *pc)
{
return elementWriteIsDenseNative(script->analysis()->poppedTypes(pc, 2),
script->analysis()->poppedTypes(pc, 1));
}
bool
TypeInferenceOracle::elementWriteIsDenseNative(StackTypeSet *obj, StackTypeSet *id)
{
// Check whether the object is a dense array and index is int32 or double.
JSValueType idType = id->getKnownTypeTag();
if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE)
return false;
Class *clasp = obj->getKnownClass();
if (!clasp || !clasp->isNative())
return false;
return obj->convertDoubleElements(cx) != StackTypeSet::AmbiguousDoubleConversion;
}
bool
TypeInferenceOracle::elementWriteIsTypedArray(RawScript script, jsbytecode *pc, int *arrayType)
{
return elementWriteIsTypedArray(script->analysis()->poppedTypes(pc, 2),
script->analysis()->poppedTypes(pc, 1),
arrayType);
}
bool
TypeInferenceOracle::elementWriteIsTypedArray(StackTypeSet *obj, StackTypeSet *id, int *arrayType)
{
// Check whether the object is a typed array and index is int32 or double.
JSValueType idType = id->getKnownTypeTag();
if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE)
return false;
*arrayType = obj->getTypedArrayType();
if (*arrayType == TypedArray::TYPE_MAX)
return false;
return true;
}
bool
TypeInferenceOracle::elementWriteNeedsDoubleConversion(RawScript script, jsbytecode *pc)
{
StackTypeSet *types = script->analysis()->poppedTypes(pc, 2);
types::StackTypeSet::DoubleConversion conversion = types->convertDoubleElements(cx);
return conversion == StackTypeSet::AlwaysConvertToDoubles ||
conversion == StackTypeSet::MaybeConvertToDoubles;
}
bool
TypeInferenceOracle::elementWriteHasExtraIndexedProperty(RawScript script, jsbytecode *pc)
{
StackTypeSet *obj = script->analysis()->poppedTypes(pc, 2);
if (obj->hasObjectFlags(cx, types::OBJECT_FLAG_LENGTH_OVERFLOW))
return true;
return types::TypeCanHaveExtraIndexedProperties(cx, obj);
}
bool
TypeInferenceOracle::elementWriteIsPacked(RawScript script, jsbytecode *pc)
{
StackTypeSet *types = script->analysis()->poppedTypes(pc, 2);
return !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
}
bool
TypeInferenceOracle::setElementHasWrittenHoles(RawScript script, jsbytecode *pc)
{
return script->analysis()->getCode(pc).arrayWriteHole;
}
MIRType
TypeInferenceOracle::elementWrite(RawScript script, jsbytecode *pc)
{
StackTypeSet *objTypes = script->analysis()->poppedTypes(pc, 2);
MIRType elementType = MIRType_None;
unsigned count = objTypes->getObjectCount();
for (unsigned i = 0; i < count; i++) {
if (objTypes->getSingleObject(i))
return MIRType_None;
if (TypeObject *object = objTypes->getTypeObject(i)) {
if (object->unknownProperties())
return MIRType_None;
types::HeapTypeSet *elementTypes = object->getProperty(cx, JSID_VOID, false);
if (!elementTypes)
return MIRType_None;
MIRType type = getMIRType(elementTypes);
if (type == MIRType_None)
return MIRType_None;
if (elementType == MIRType_None)
elementType = type;
else if (elementType != type)
return MIRType_None;
}
}
return elementType;
}
bool
TypeInferenceOracle::arrayResultShouldHaveDoubleConversion(RawScript script, jsbytecode *pc)
{
types::StackTypeSet::DoubleConversion conversion =
script->analysis()->pushedTypes(pc, 0)->convertDoubleElements(cx);
return conversion == types::StackTypeSet::AlwaysConvertToDoubles;
}
bool
TypeInferenceOracle::propertyWriteCanSpecialize(RawScript script, jsbytecode *pc)
{
return !script->analysis()->getCode(pc).monitoredTypes;
}
bool
TypeInferenceOracle::propertyWriteNeedsBarrier(RawScript script, jsbytecode *pc, RawId id)
{
StackTypeSet *types = script->analysis()->poppedTypes(pc, 1);
return types->propertyNeedsBarrier(cx, id);
}
bool
TypeInferenceOracle::elementWriteNeedsBarrier(RawScript script, jsbytecode *pc)
{
// Return true if SETELEM-like instructions need a write barrier before modifying
// a property. The object is the third value popped by SETELEM.
return elementWriteNeedsBarrier(script->analysis()->poppedTypes(pc, 2));
}
bool
TypeInferenceOracle::elementWriteNeedsBarrier(StackTypeSet *obj)
{
return obj->propertyNeedsBarrier(cx, JSID_VOID);
}
StackTypeSet *
TypeInferenceOracle::getCallTarget(RawScript caller, uint32_t argc, jsbytecode *pc)
{
JS_ASSERT(caller == this->script());
JS_ASSERT(js_CodeSpec[*pc].format & JOF_INVOKE);
ScriptAnalysis *analysis = script()->analysis();
return analysis->poppedTypes(pc, argc + 1);
}
StackTypeSet *
TypeInferenceOracle::getCallArg(RawScript script, uint32_t argc, uint32_t arg, jsbytecode *pc)
{
JS_ASSERT(argc >= arg);
// Bytecode order: Function, This, Arg0, Arg1, ..., ArgN, Call.
// |argc| does not include |this|.
return script->analysis()->poppedTypes(pc, argc - arg);
}
StackTypeSet *
TypeInferenceOracle::getCallReturn(RawScript script, jsbytecode *pc)
{
return script->analysis()->pushedTypes(pc, 0);
}
bool
TypeInferenceOracle::canInlineCall(HandleScript caller, jsbytecode *pc)
{
JS_ASSERT(types::IsInlinableCall(pc));
JSOp op = JSOp(*pc);
Bytecode *code = caller->analysis()->maybeCode(pc);
// For foo.apply(this, arguments), the caller is foo and not the js_fun_apply function.
// Ignore code->monitoredTypes, as we know the caller is foo
if (op != JSOP_FUNAPPLY && code->monitoredTypes)
return false;
return true;
}
types::TypeBarrier*
TypeInferenceOracle::callArgsBarrier(HandleScript caller, jsbytecode *pc)
{
JS_ASSERT(types::IsInlinableCall(pc));
return caller->analysis()->typeBarriers(cx, pc);
}
bool
TypeInferenceOracle::canEnterInlinedFunction(RawFunction target)
{
RootedScript targetScript(cx, target->nonLazyScript());
// Make sure empty script has type information, to allow inlining in more cases.
if (targetScript->length == 1) {
if (!targetScript->ensureRanInference(cx))
return false;
}
if (!targetScript->hasAnalysis() ||
!targetScript->analysis()->ranInference() ||
!targetScript->analysis()->ranSSA())
{
return false;
}
if (!targetScript->analysis()->ionInlineable())
return false;
if (targetScript->needsArgsObj())
return false;
if (!targetScript->compileAndGo)
return false;
if (targetScript->analysis()->usesScopeChain())
return false;
types::TypeObject *targetType = target->getType(cx);
if (!targetType || targetType->unknownProperties())
return false;
// TI calls ObjectStateChange to trigger invalidation of the caller.
HeapTypeSet::WatchObjectStateChange(cx, targetType);
return true;
}
bool
TypeInferenceOracle::callReturnTypeSetMatches(RawScript callerScript, jsbytecode *callerPc,
RawFunction callee)
{
RootedScript targetScript(cx, callee->nonLazyScript());
JSOp op = JSOp(*callerPc);
TypeSet *returnTypes = TypeScript::ReturnTypes(targetScript);
TypeSet *callReturn = getCallReturn(callerScript, callerPc);
if (op == JSOP_NEW) {
if (!returnTypes->isSubsetIgnorePrimitives(callReturn))
return false;
} else {
if (!returnTypes->isSubset(callReturn))
return false;
}
return true;
}
bool
TypeInferenceOracle::callArgsTypeSetMatches(types::StackTypeSet *thisType, Vector<types::StackTypeSet *> &argvType, RawFunction callee)
{
RootedScript targetScript(cx, callee->nonLazyScript());
types::TypeSet *calleeType;
size_t nargs = Min<size_t>(callee->nargs, argvType.length());
// This
calleeType = types::TypeScript::ThisTypes(targetScript);
if (!thisType->isSubset(calleeType))
return false;
// Arguments
for (size_t i = 0; i < nargs; i++) {
calleeType = types::TypeScript::ArgTypes(targetScript, i);
if (!argvType[i]->isSubset(calleeType))
return false;
}
// Arguments that weren't provided will be Undefined
for (size_t i = nargs; i < callee->nargs; i++) {
calleeType = types::TypeScript::ArgTypes(targetScript, i);
if (calleeType->unknown() ||
!calleeType->hasType(types::Type::UndefinedType()))
{
return false;
}
}
return true;
}
bool
TypeInferenceOracle::callArgsTypeSetIntersects(types::StackTypeSet *thisType, Vector<types::StackTypeSet *> &argvType, RawFunction callee)
{
RootedScript targetScript(cx, callee->nonLazyScript());
types::TypeSet *calleeType;
size_t nargs = Min<size_t>(callee->nargs, argvType.length());
// This
if (thisType) {
calleeType = types::TypeScript::ThisTypes(targetScript);
if (thisType->intersectionEmpty(calleeType))
return false;
}
// Arguments
for (size_t i = 0; i < nargs; i++) {
calleeType = types::TypeScript::ArgTypes(targetScript, i);
if (argvType[i]->intersectionEmpty(calleeType))
return false;
}
// Arguments that weren't provided will be Undefined
for (size_t i = nargs; i < callee->nargs; i++) {
calleeType = types::TypeScript::ArgTypes(targetScript, i);
if (calleeType->unknown() ||
!calleeType->hasType(types::Type::UndefinedType()))
{
return false;
}
}
return true;
}
HeapTypeSet *
TypeInferenceOracle::globalPropertyWrite(RawScript script, jsbytecode *pc, jsid id,
bool *canSpecialize)
{
*canSpecialize = !script->analysis()->getCode(pc).monitoredTypes;
if (!*canSpecialize)
return NULL;
return globalPropertyTypeSet(script, pc, id);
}
StackTypeSet *
TypeInferenceOracle::returnTypeSet(RawScript script, jsbytecode *pc, types::StackTypeSet **barrier)
{
if (script->analysis()->getCode(pc).monitoredTypesReturn)
*barrier = script->analysis()->bytecodeTypes(pc);
else
*barrier = NULL;
return script->analysis()->pushedTypes(pc, 0);
}
StackTypeSet *
TypeInferenceOracle::aliasedVarBarrier(RawScript script, jsbytecode *pc, types::StackTypeSet **barrier)
{
*barrier = script->analysis()->bytecodeTypes(pc);
return script->analysis()->pushedTypes(pc, 0);
}
HeapTypeSet *
TypeInferenceOracle::globalPropertyTypeSet(RawScript script, jsbytecode *pc, jsid id)
{
TypeObject *type = script->global().getType(cx);
if (!type || type->unknownProperties())
return NULL;
return type->getProperty(cx, id, false);
}
LazyArgumentsType
TypeInferenceOracle::isArgumentObject(types::StackTypeSet *obj)
{
if (obj->isMagicArguments())
return DefinitelyArguments;
if (obj->hasAnyFlag(TYPE_FLAG_LAZYARGS))
return MaybeArguments;
return NotArguments;
}
LazyArgumentsType
TypeInferenceOracle::propertyReadMagicArguments(RawScript script, jsbytecode *pc)
{
StackTypeSet *obj = script->analysis()->poppedTypes(pc, 0);
return isArgumentObject(obj);
}
LazyArgumentsType
TypeInferenceOracle::elementReadMagicArguments(RawScript script, jsbytecode *pc)
{
StackTypeSet *obj = script->analysis()->poppedTypes(pc, 1);
return isArgumentObject(obj);
}
LazyArgumentsType
TypeInferenceOracle::elementWriteMagicArguments(RawScript script, jsbytecode *pc)
{
StackTypeSet *obj = script->analysis()->poppedTypes(pc, 2);
return isArgumentObject(obj);
}

View File

@ -1,421 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef js_ion_type_oracle_h__
#define js_ion_type_oracle_h__
#include "jsscript.h"
#include "IonTypes.h"
namespace js {
namespace ion {
enum LazyArgumentsType {
MaybeArguments = 0,
DefinitelyArguments,
NotArguments
};
class TypeOracle
{
public:
struct UnaryTypes {
types::StackTypeSet *inTypes;
types::StackTypeSet *outTypes;
};
struct BinaryTypes {
types::StackTypeSet *lhsTypes;
types::StackTypeSet *rhsTypes;
types::StackTypeSet *outTypes;
};
struct Unary {
MIRType ival;
MIRType rval;
};
struct Binary {
MIRType lhs;
MIRType rhs;
MIRType rval;
};
public:
virtual UnaryTypes unaryTypes(RawScript script, jsbytecode *pc) = 0;
virtual BinaryTypes binaryTypes(RawScript script, jsbytecode *pc) = 0;
virtual Unary unaryOp(RawScript script, jsbytecode *pc) = 0;
virtual Binary binaryOp(RawScript script, jsbytecode *pc) = 0;
virtual types::StackTypeSet *thisTypeSet(RawScript script) { return NULL; }
virtual bool getOsrTypes(jsbytecode *osrPc, Vector<MIRType> &slotTypes) { return true; }
virtual types::StackTypeSet *parameterTypeSet(RawScript script, size_t index) { return NULL; }
virtual types::HeapTypeSet *globalPropertyTypeSet(RawScript script, jsbytecode *pc, jsid id) {
return NULL;
}
virtual types::StackTypeSet *propertyRead(RawScript script, jsbytecode *pc) {
return NULL;
}
virtual types::StackTypeSet *propertyReadBarrier(HandleScript script, jsbytecode *pc) {
return NULL;
}
virtual bool propertyReadIdempotent(HandleScript script, jsbytecode *pc, HandleId id) {
return false;
}
virtual bool propertyReadAccessGetter(RawScript script, jsbytecode *pc) {
return false;
}
virtual types::HeapTypeSet *globalPropertyWrite(RawScript script, jsbytecode *pc,
jsid id, bool *canSpecialize) {
*canSpecialize = true;
return NULL;
}
virtual types::StackTypeSet *returnTypeSet(RawScript script, jsbytecode *pc, types::StackTypeSet **barrier) {
*barrier = NULL;
return NULL;
}
virtual bool inObjectIsDenseNativeWithoutExtraIndexedProperties(HandleScript script, jsbytecode *pc) {
return false;
}
virtual bool inArrayIsPacked(RawScript script, jsbytecode *pc) {
return false;
}
virtual bool elementReadIsDenseNative(RawScript script, jsbytecode *pc) {
return false;
}
virtual bool elementReadIsTypedArray(RawScript script, jsbytecode *pc, int *arrayType) {
return false;
}
virtual bool elementReadIsString(RawScript script, jsbytecode *pc) {
return false;
}
virtual bool elementReadShouldAlwaysLoadDoubles(RawScript script, jsbytecode *pc) {
return false;
}
virtual bool elementReadHasExtraIndexedProperty(RawScript, jsbytecode *pc) {
return false;
}
virtual bool elementReadIsPacked(RawScript script, jsbytecode *pc) {
return false;
}
virtual void elementReadGeneric(RawScript script, jsbytecode *pc, bool *cacheable, bool *monitorResult, bool *intIndex) {
*cacheable = false;
*monitorResult = true;
*intIndex = false;
}
virtual bool setElementHasWrittenHoles(RawScript script, jsbytecode *pc) {
return true;
}
virtual bool elementWriteIsDenseNative(HandleScript script, jsbytecode *pc) {
return false;
}
virtual bool elementWriteIsDenseNative(types::StackTypeSet *obj, types::StackTypeSet *id) {
return false;
}
virtual bool elementWriteIsTypedArray(RawScript script, jsbytecode *pc, int *arrayType) {
return false;
}
virtual bool elementWriteIsTypedArray(types::StackTypeSet *obj, types::StackTypeSet *id, int *arrayType) {
return false;
}
virtual bool elementWriteNeedsDoubleConversion(RawScript script, jsbytecode *pc) {
return false;
}
virtual bool elementWriteHasExtraIndexedProperty(RawScript script, jsbytecode *pc) {
return false;
}
virtual bool elementWriteIsPacked(RawScript script, jsbytecode *pc) {
return false;
}
virtual bool arrayResultShouldHaveDoubleConversion(RawScript script, jsbytecode *pc) {
return false;
}
virtual bool propertyWriteCanSpecialize(RawScript script, jsbytecode *pc) {
return true;
}
virtual bool propertyWriteNeedsBarrier(RawScript script, jsbytecode *pc, RawId id) {
return true;
}
virtual bool elementWriteNeedsBarrier(RawScript script, jsbytecode *pc) {
return true;
}
virtual bool elementWriteNeedsBarrier(types::StackTypeSet *obj) {
return true;
}
virtual MIRType elementWrite(RawScript script, jsbytecode *pc) {
return MIRType_None;
}
/* |pc| must be a |JSOP_CALL|. */
virtual types::StackTypeSet *getCallTarget(RawScript caller, uint32_t argc, jsbytecode *pc) {
// Same assertion as TypeInferenceOracle::getCallTarget.
JS_ASSERT(js_CodeSpec[*pc].format & JOF_INVOKE && JSOp(*pc) != JSOP_EVAL);
return NULL;
}
virtual types::StackTypeSet *getCallArg(RawScript script, uint32_t argc, uint32_t arg, jsbytecode *pc) {
return NULL;
}
virtual types::StackTypeSet *getCallReturn(RawScript script, jsbytecode *pc) {
return NULL;
}
virtual bool canInlineCall(HandleScript caller, jsbytecode *pc) {
return false;
}
virtual types::TypeBarrier *callArgsBarrier(HandleScript caller, jsbytecode *pc) {
return NULL;
}
virtual bool canEnterInlinedFunction(RawFunction callee) {
return false;
}
virtual bool callReturnTypeSetMatches(RawScript callerScript, jsbytecode *callerPc,
RawFunction callee)
{
return false;
}
virtual bool callArgsTypeSetIntersects(types::StackTypeSet *thisType, Vector<types::StackTypeSet *> &argvType, RawFunction callee)
{
return false;
}
virtual bool callArgsTypeSetMatches(types::StackTypeSet *thisType, Vector<types::StackTypeSet *> &argvType, RawFunction callee)
{
return false;
}
virtual types::StackTypeSet *aliasedVarBarrier(RawScript script, jsbytecode *pc,
types::StackTypeSet **barrier)
{
return NULL;
}
virtual LazyArgumentsType isArgumentObject(types::StackTypeSet *obj) {
return MaybeArguments;
}
virtual LazyArgumentsType propertyReadMagicArguments(RawScript script, jsbytecode *pc) {
return MaybeArguments;
}
virtual LazyArgumentsType elementReadMagicArguments(RawScript script, jsbytecode *pc) {
return MaybeArguments;
}
virtual LazyArgumentsType elementWriteMagicArguments(RawScript script, jsbytecode *pc) {
return MaybeArguments;
}
};
class DummyOracle : public TypeOracle
{
public:
UnaryTypes unaryTypes(RawScript script, jsbytecode *pc) {
UnaryTypes u;
u.inTypes = NULL;
u.outTypes = NULL;
return u;
}
BinaryTypes binaryTypes(RawScript script, jsbytecode *pc) {
BinaryTypes b;
b.lhsTypes = NULL;
b.rhsTypes = NULL;
b.outTypes = NULL;
return b;
}
Unary unaryOp(RawScript script, jsbytecode *pc) {
Unary u;
u.ival = MIRType_Int32;
u.rval = MIRType_Int32;
return u;
}
Binary binaryOp(RawScript script, jsbytecode *pc) {
Binary b;
b.lhs = MIRType_Int32;
b.rhs = MIRType_Int32;
b.rval = MIRType_Int32;
return b;
}
};
class TypeInferenceOracle : public TypeOracle
{
JSContext *cx;
HeapPtrScript script_;
MIRType getMIRType(types::StackTypeSet *types);
MIRType getMIRType(types::HeapTypeSet *types);
bool analyzeTypesForInlinableCallees(JSContext *cx, JSScript *script,
Vector<JSScript*> &seen);
bool analyzeTypesForInlinableCallees(JSContext *cx, types::StackTypeSet *calleeTypes,
Vector<JSScript*> &seen);
public:
TypeInferenceOracle();
bool init(JSContext *cx, JSScript *script, bool inlinedCall);
RawScript script() { return script_.get(); }
UnaryTypes unaryTypes(RawScript script, jsbytecode *pc);
BinaryTypes binaryTypes(RawScript script, jsbytecode *pc);
Unary unaryOp(RawScript script, jsbytecode *pc);
Binary binaryOp(RawScript script, jsbytecode *pc);
types::StackTypeSet *thisTypeSet(RawScript script);
bool getOsrTypes(jsbytecode *osrPc, Vector<MIRType> &slotTypes);
types::StackTypeSet *parameterTypeSet(RawScript script, size_t index);
types::HeapTypeSet *globalPropertyTypeSet(RawScript script, jsbytecode *pc, jsid id);
types::StackTypeSet *propertyRead(RawScript script, jsbytecode *pc);
types::StackTypeSet *propertyReadBarrier(HandleScript script, jsbytecode *pc);
bool propertyReadIdempotent(HandleScript script, jsbytecode *pc, HandleId id);
bool propertyReadAccessGetter(RawScript script, jsbytecode *pc);
types::HeapTypeSet *globalPropertyWrite(RawScript script, jsbytecode *pc, jsid id, bool *canSpecialize);
types::StackTypeSet *returnTypeSet(RawScript script, jsbytecode *pc, types::StackTypeSet **barrier);
types::StackTypeSet *getCallTarget(RawScript caller, uint32_t argc, jsbytecode *pc);
types::StackTypeSet *getCallArg(RawScript caller, uint32_t argc, uint32_t arg, jsbytecode *pc);
types::StackTypeSet *getCallReturn(RawScript caller, jsbytecode *pc);
bool inObjectIsDenseNativeWithoutExtraIndexedProperties(HandleScript script, jsbytecode *pc);
bool inArrayIsPacked(RawScript script, jsbytecode *pc);
bool elementReadIsDenseNative(RawScript script, jsbytecode *pc);
bool elementReadIsTypedArray(RawScript script, jsbytecode *pc, int *atype);
bool elementReadIsString(RawScript script, jsbytecode *pc);
bool elementReadShouldAlwaysLoadDoubles(RawScript script, jsbytecode *pc);
bool elementReadHasExtraIndexedProperty(RawScript, jsbytecode *pc);
bool elementReadIsPacked(RawScript script, jsbytecode *pc);
void elementReadGeneric(RawScript script, jsbytecode *pc, bool *cacheable, bool *monitorResult, bool *intIndex);
bool elementWriteIsDenseNative(HandleScript script, jsbytecode *pc);
bool elementWriteIsDenseNative(types::StackTypeSet *obj, types::StackTypeSet *id);
bool elementWriteIsTypedArray(RawScript script, jsbytecode *pc, int *arrayType);
bool elementWriteIsTypedArray(types::StackTypeSet *obj, types::StackTypeSet *id, int *arrayType);
bool elementWriteNeedsDoubleConversion(RawScript script, jsbytecode *pc);
bool elementWriteHasExtraIndexedProperty(RawScript script, jsbytecode *pc);
bool elementWriteIsPacked(RawScript script, jsbytecode *pc);
bool arrayResultShouldHaveDoubleConversion(RawScript script, jsbytecode *pc);
bool setElementHasWrittenHoles(RawScript script, jsbytecode *pc);
bool propertyWriteCanSpecialize(RawScript script, jsbytecode *pc);
bool propertyWriteNeedsBarrier(RawScript script, jsbytecode *pc, RawId id);
bool elementWriteNeedsBarrier(RawScript script, jsbytecode *pc);
bool elementWriteNeedsBarrier(types::StackTypeSet *obj);
MIRType elementWrite(RawScript script, jsbytecode *pc);
bool canInlineCall(HandleScript caller, jsbytecode *pc);
types::TypeBarrier *callArgsBarrier(HandleScript caller, jsbytecode *pc);
bool canEnterInlinedFunction(RawFunction callee);
bool callReturnTypeSetMatches(RawScript callerScript, jsbytecode *callerPc, RawFunction callee);
bool callArgsTypeSetIntersects(types::StackTypeSet *thisType, Vector<types::StackTypeSet *> &argvType, RawFunction callee);
bool callArgsTypeSetMatches(types::StackTypeSet *thisType, Vector<types::StackTypeSet *> &argvType, RawFunction callee);
types::StackTypeSet *aliasedVarBarrier(RawScript script, jsbytecode *pc, types::StackTypeSet **barrier);
LazyArgumentsType isArgumentObject(types::StackTypeSet *obj);
LazyArgumentsType propertyReadMagicArguments(RawScript script, jsbytecode *pc);
LazyArgumentsType elementReadMagicArguments(RawScript script, jsbytecode *pc);
LazyArgumentsType elementWriteMagicArguments(RawScript script, jsbytecode *pc);
};
static inline MIRType
MIRTypeFromValueType(JSValueType type)
{
switch (type) {
case JSVAL_TYPE_DOUBLE:
return MIRType_Double;
case JSVAL_TYPE_INT32:
return MIRType_Int32;
case JSVAL_TYPE_UNDEFINED:
return MIRType_Undefined;
case JSVAL_TYPE_STRING:
return MIRType_String;
case JSVAL_TYPE_BOOLEAN:
return MIRType_Boolean;
case JSVAL_TYPE_NULL:
return MIRType_Null;
case JSVAL_TYPE_OBJECT:
return MIRType_Object;
case JSVAL_TYPE_MAGIC:
return MIRType_Magic;
case JSVAL_TYPE_UNKNOWN:
return MIRType_Value;
default:
JS_NOT_REACHED("unexpected jsval type");
return MIRType_None;
}
}
static inline JSValueType
ValueTypeFromMIRType(MIRType type)
{
switch (type) {
case MIRType_Undefined:
return JSVAL_TYPE_UNDEFINED;
case MIRType_Null:
return JSVAL_TYPE_NULL;
case MIRType_Boolean:
return JSVAL_TYPE_BOOLEAN;
case MIRType_Int32:
return JSVAL_TYPE_INT32;
case MIRType_Double:
return JSVAL_TYPE_DOUBLE;
case MIRType_String:
return JSVAL_TYPE_STRING;
case MIRType_Magic:
return JSVAL_TYPE_MAGIC;
default:
JS_ASSERT(type == MIRType_Object);
return JSVAL_TYPE_OBJECT;
}
}
static inline JSValueTag
MIRTypeToTag(MIRType type)
{
return JSVAL_TYPE_TO_TAG(ValueTypeFromMIRType(type));
}
static inline const char *
StringFromMIRType(MIRType type)
{
switch (type) {
case MIRType_Undefined:
return "Undefined";
case MIRType_Null:
return "Null";
case MIRType_Boolean:
return "Bool";
case MIRType_Int32:
return "Int32";
case MIRType_Double:
return "Double";
case MIRType_String:
return "String";
case MIRType_Object:
return "Object";
case MIRType_Magic:
return "Magic";
case MIRType_Value:
return "Value";
case MIRType_None:
return "None";
case MIRType_Slots:
return "Slots";
case MIRType_Elements:
return "Elements";
case MIRType_Pointer:
return "Pointer";
case MIRType_ForkJoinSlice:
return "ForkJoinSlice";
default:
JS_NOT_REACHED("Unknown MIRType.");
return "";
}
}
static inline bool
IsNumberType(MIRType type)
{
return type == MIRType_Int32 || type == MIRType_Double;
}
static inline bool
IsNullOrUndefined(MIRType type)
{
return type == MIRType_Null || type == MIRType_Undefined;
}
} /* ion */
} /* js */
#endif // js_ion_type_oracle_h__

View File

@ -7,7 +7,7 @@
#ifndef jsion_type_policy_h__
#define jsion_type_policy_h__
#include "TypeOracle.h"
#include "IonTypes.h"
namespace js {
namespace ion {

View File

@ -1541,14 +1541,22 @@ CodeGeneratorARM::storeElementTyped(const LAllocation *value, MIRType valueType,
}
bool
CodeGeneratorARM::visitGuardShape(LGuardShape *guard)
CodeGeneratorARM::visitGuardShapeOrType(LGuardShapeOrType *guard)
{
Register obj = ToRegister(guard->input());
Register tmp = ToRegister(guard->tempInt());
masm.ma_ldr(DTRAddr(obj, DtrOffImm(JSObject::offsetOfShape())), tmp);
masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->shape()));
if (!bailoutIf(Assembler::NotEqual, guard->snapshot()))
if (guard->mir()->shape()) {
masm.ma_ldr(DTRAddr(obj, DtrOffImm(JSObject::offsetOfShape())), tmp);
masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->shape()));
} else {
masm.ma_ldr(DTRAddr(obj, DtrOffImm(JSObject::offsetOfType())), tmp);
masm.ma_cmp(tmp, ImmGCPtr(guard->mir()->typeObject()));
}
Assembler::Condition cond =
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
if (!bailoutIf(cond, guard->snapshot()))
return false;
return true;
}

View File

@ -134,7 +134,7 @@ class CodeGeneratorARM : public CodeGeneratorShared
bool visitLoadElementT(LLoadElementT *load);
bool visitGuardShape(LGuardShape *guard);
bool visitGuardShapeOrType(LGuardShapeOrType *guard);
bool visitGuardClass(LGuardClass *guard);
bool visitImplicitThis(LImplicitThis *lir);

View File

@ -7,7 +7,7 @@
#ifndef jsion_lir_arm_h__
#define jsion_lir_arm_h__
#include "ion/TypeOracle.h"
#include "ion/LIR.h"
namespace js {
namespace ion {
@ -263,17 +263,17 @@ class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 2>
};
// Guard against an object's shape.
class LGuardShape : public LInstructionHelper<0, 1, 1>
class LGuardShapeOrType : public LInstructionHelper<0, 1, 1>
{
public:
LIR_HEADER(GuardShape);
LIR_HEADER(GuardShapeOrType);
LGuardShape(const LAllocation &in, const LDefinition &temp) {
LGuardShapeOrType(const LAllocation &in, const LDefinition &temp) {
setOperand(0, in);
setTemp(0, temp);
}
const MGuardShape *mir() const {
return mir_->toGuardShape();
const MGuardShapeOrType *mir() const {
return mir_->toGuardShapeOrType();
}
const LAllocation *tempInt() {
return getTemp(0)->output();

View File

@ -302,12 +302,12 @@ LIRGeneratorARM::newLGetPropertyCacheT(MGetPropertyCache *ins)
}
bool
LIRGeneratorARM::visitGuardShape(MGuardShape *ins)
LIRGeneratorARM::visitGuardShapeOrType(MGuardShapeOrType *ins)
{
JS_ASSERT(ins->obj()->type() == MIRType_Object);
LDefinition tempObj = temp(LDefinition::OBJECT);
LGuardShape *guard = new LGuardShape(useRegister(ins->obj()), tempObj);
LGuardShapeOrType *guard = new LGuardShapeOrType(useRegister(ins->obj()), tempObj);
if (!assignSnapshot(guard, ins->bailoutKind()))
return false;
if (!add(guard, ins))

View File

@ -64,7 +64,7 @@ class LIRGeneratorARM : public LIRGeneratorShared
bool visitUnbox(MUnbox *unbox);
bool visitReturn(MReturn *ret);
bool lowerPhi(MPhi *phi);
bool visitGuardShape(MGuardShape *ins);
bool visitGuardShapeOrType(MGuardShapeOrType *ins);
bool visitStoreTypedArrayElement(MStoreTypedArrayElement *ins);
bool visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole *ins);
bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);

View File

@ -1302,11 +1302,17 @@ CodeGeneratorX86Shared::visitRound(LRound *lir)
}
bool
CodeGeneratorX86Shared::visitGuardShape(LGuardShape *guard)
CodeGeneratorX86Shared::visitGuardShapeOrType(LGuardShapeOrType *guard)
{
Register obj = ToRegister(guard->input());
masm.cmpPtr(Operand(obj, JSObject::offsetOfShape()), ImmGCPtr(guard->mir()->shape()));
if (!bailoutIf(Assembler::NotEqual, guard->snapshot()))
if (guard->mir()->shape())
masm.cmpPtr(Operand(obj, JSObject::offsetOfShape()), ImmGCPtr(guard->mir()->shape()));
else
masm.cmpPtr(Operand(obj, JSObject::offsetOfType()), ImmGCPtr(guard->mir()->typeObject()));
Assembler::Condition cond =
guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
if (!bailoutIf(cond, guard->snapshot()))
return false;
return true;
}

View File

@ -102,7 +102,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
virtual bool visitMathD(LMathD *math);
virtual bool visitFloor(LFloor *lir);
virtual bool visitRound(LRound *lir);
virtual bool visitGuardShape(LGuardShape *guard);
virtual bool visitGuardShapeOrType(LGuardShapeOrType *guard);
virtual bool visitGuardClass(LGuardClass *guard);
virtual bool visitEffectiveAddress(LEffectiveAddress *ins);
virtual bool visitAsmJSDivOrMod(LAsmJSDivOrMod *ins);

View File

@ -174,16 +174,16 @@ class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 3>
};
// Guard against an object's shape.
class LGuardShape : public LInstructionHelper<0, 1, 0>
class LGuardShapeOrType : public LInstructionHelper<0, 1, 0>
{
public:
LIR_HEADER(GuardShape)
LIR_HEADER(GuardShapeOrType)
LGuardShape(const LAllocation &in) {
LGuardShapeOrType(const LAllocation &in) {
setOperand(0, in);
}
const MGuardShape *mir() const {
return mir_->toGuardShape();
const MGuardShapeOrType *mir() const {
return mir_->toGuardShapeOrType();
}
};

View File

@ -401,6 +401,9 @@ LIRGeneratorShared::add(T *ins, MInstruction *mir)
static inline uint32_t
VirtualRegisterOfPayload(MDefinition *mir)
{
// Type barriers may have box inputs, and pass through their input's vreg.
while (mir->isTypeBarrier())
mir = mir->getOperand(0);
if (mir->isBox()) {
MDefinition *inner = mir->toBox()->getOperand(0);
if (!inner->isConstant() && inner->type() != MIRType_Double)

View File

@ -36,11 +36,11 @@ LIRGeneratorX86Shared::visitInterruptCheck(MInterruptCheck *ins)
}
bool
LIRGeneratorX86Shared::visitGuardShape(MGuardShape *ins)
LIRGeneratorX86Shared::visitGuardShapeOrType(MGuardShapeOrType *ins)
{
JS_ASSERT(ins->obj()->type() == MIRType_Object);
LGuardShape *guard = new LGuardShape(useRegister(ins->obj()));
LGuardShapeOrType *guard = new LGuardShapeOrType(useRegister(ins->obj()));
if (!assignSnapshot(guard, ins->bailoutKind()))
return false;
if (!add(guard, ins))

View File

@ -24,7 +24,7 @@ class LIRGeneratorX86Shared : public LIRGeneratorShared
LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
bool visitInterruptCheck(MInterruptCheck *ins);
bool visitGuardShape(MGuardShape *ins);
bool visitGuardShapeOrType(MGuardShapeOrType *ins);
bool visitPowHalf(MPowHalf *ins);
bool visitConstant(MConstant *ins);
bool visitAsmJSNeg(MAsmJSNeg *ins);

View File

@ -7,7 +7,7 @@
#ifndef jsion_lir_x64_h__
#define jsion_lir_x64_h__
#include "ion/TypeOracle.h"
#include "ion/LIR.h"
namespace js {
namespace ion {

View File

@ -7,7 +7,7 @@
#ifndef jsion_lir_x86_h__
#define jsion_lir_x86_h__
#include "ion/TypeOracle.h"
#include "ion/LIR.h"
namespace js {
namespace ion {

View File

@ -0,0 +1,17 @@
try {
arguments.toSource = (function() {
__proto__.y = x
})
y = this
print(x = 8)
a = arguments
for (v of this) {}
} catch (e) {}
function f() {
"HELLO " + y
}
f()
f()
y = 1[7]
f()

View File

@ -0,0 +1,14 @@
try {
x = evalcx('')
toSource = (function() {
x = (new WeakMap).get(function() {})
})
valueOf = (function() {
schedulegc(x)
})
this + ''
for (v of this) {}
} catch (e) {}
gc()
this + 1

View File

@ -326,6 +326,25 @@ types::TypeFailure(JSContext *cx, const char *fmt, ...)
// TypeSet
/////////////////////////////////////////////////////////////////////
TypeSet::TypeSet(Type type)
: flags(0), objectSet(NULL), constraintList(NULL)
{
if (type.isUnknown()) {
flags |= TYPE_FLAG_BASE_MASK;
} else if (type.isPrimitive()) {
flags = PrimitiveTypeFlag(type.primitive());
if (flags == TYPE_FLAG_DOUBLE)
flags |= TYPE_FLAG_INT32;
} else if (type.isAnyObject()) {
flags |= TYPE_FLAG_ANYOBJECT;
} else if (type.isTypeObject() && type.typeObject()->unknownProperties()) {
flags |= TYPE_FLAG_ANYOBJECT;
} else {
setBaseObjectCount(1);
objectSet = reinterpret_cast<TypeObjectKey**>(type.objectKey());
}
}
bool
TypeSet::isSubset(TypeSet *other)
{
@ -541,7 +560,7 @@ StackTypeSet::make(JSContext *cx, const char *name)
return res;
}
const StackTypeSet *
StackTypeSet *
TypeSet::clone(LifoAlloc *alloc) const
{
unsigned objectCount = baseObjectCount();
@ -565,6 +584,55 @@ TypeSet::clone(LifoAlloc *alloc) const
return res;
}
bool
TypeSet::addObject(TypeObjectKey *key, LifoAlloc *alloc)
{
JS_ASSERT(!constraintList);
uint32_t objectCount = baseObjectCount();
TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
(*alloc, objectSet, objectCount, key);
if (!pentry)
return false;
if (*pentry)
return true;
*pentry = key;
setBaseObjectCount(objectCount);
if (objectCount == TYPE_FLAG_OBJECT_COUNT_LIMIT) {
flags |= TYPE_FLAG_ANYOBJECT;
clearObjects();
}
return true;
}
/* static */ StackTypeSet *
TypeSet::unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc)
{
StackTypeSet *res = alloc->new_<StackTypeSet>();
if (!res)
return NULL;
res->flags = a->baseFlags() | b->baseFlags();
if (!res->unknownObject()) {
for (size_t i = 0; i < a->getObjectCount() && !res->unknownObject(); i++) {
TypeObjectKey *key = a->getObject(i);
if (key && !res->addObject(key, alloc))
return NULL;
}
for (size_t i = 0; i < b->getObjectCount() && !res->unknownObject(); i++) {
TypeObjectKey *key = b->getObject(i);
if (key && !res->addObject(key, alloc))
return NULL;
}
}
return res;
}
/////////////////////////////////////////////////////////////////////
// TypeSet constraints
/////////////////////////////////////////////////////////////////////
@ -1789,6 +1857,18 @@ HeapTypeSet::getKnownTypeTag(JSContext *cx)
return type;
}
bool
StackTypeSet::mightBeType(JSValueType type)
{
if (unknown())
return true;
if (type == JSVAL_TYPE_OBJECT)
return unknownObject() || baseObjectCount() != 0;
return baseFlags() & PrimitiveTypeFlag(type);
}
/* Constraint which triggers recompilation if an object acquires particular flags. */
class TypeConstraintFreezeObjectFlags : public TypeConstraint
{
@ -4867,11 +4947,7 @@ ScriptAnalysis::analyzeTypes(JSContext *cx)
result = result->next;
}
if (!script_->hasFreezeConstraints) {
RootedScript script(cx, script_);
TypeScript::AddFreezeConstraints(cx, script);
script_->hasFreezeConstraints = true;
}
TypeScript::AddFreezeConstraints(cx, script_);
}
bool
@ -5087,6 +5163,18 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, HandleFunction fun,
SSAValue thisv = SSAValue::PushedValue(offset, 0);
SSAUseChain *uses = analysis->useChain(thisv);
/*
* If offset >= the offset at the top of the pending stack, we either
* encountered the end of a compound inline assignment or a 'this' was
* immediately popped and used. In either case, handle the use.
*/
if (!pendingPoppedThis.empty() &&
offset >= pendingPoppedThis.back()->offset) {
lastThisPopped = pendingPoppedThis[0]->offset;
if (!AnalyzePoppedThis(cx, &pendingPoppedThis, type, fun, state))
return false;
}
JS_ASSERT(uses);
if (uses->next || !uses->popped) {
/* 'this' value popped in more than one place. */
@ -5101,18 +5189,6 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, HandleFunction fun,
break;
}
/*
* If offset >= the offset at the top of the pending stack, we either
* encountered the end of a compound inline assignment or a 'this' was
* immediately popped and used. In either case, handle the use.
*/
if (!pendingPoppedThis.empty() &&
offset >= pendingPoppedThis.back()->offset) {
lastThisPopped = pendingPoppedThis[0]->offset;
if (!AnalyzePoppedThis(cx, &pendingPoppedThis, type, fun, state))
return false;
}
if (!pendingPoppedThis.append(uses)) {
entirelyAnalyzed = false;
break;
@ -6005,48 +6081,6 @@ JSFunction::setTypeForScriptedFunction(JSContext *cx, HandleFunction fun, bool s
return true;
}
#ifdef DEBUG
/* static */ void
TypeScript::CheckBytecode(JSContext *cx, HandleScript script, jsbytecode *pc, const js::Value *sp)
{
AutoEnterAnalysis enter(cx);
if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
return;
if (!script->hasAnalysis() || !script->analysis()->ranInference())
return;
ScriptAnalysis *analysis = script->analysis();
int defCount = GetDefCount(script, pc - script->code);
for (int i = 0; i < defCount; i++) {
const js::Value &val = sp[-defCount + i];
TypeSet *types = analysis->pushedTypes(pc, i);
if (IgnorePushed(pc, i))
continue;
/*
* Ignore undefined values, these may have been inserted by Ion to
* substitute for dead values.
*/
if (val.isUndefined())
continue;
Type type = GetValueType(cx, val);
if (!types->hasType(type)) {
/* Display fine-grained debug information first */
fprintf(stderr, "Missing type at #%u:%05u pushed %u: %s\n",
script->id(), unsigned(pc - script->code), i, TypeString(type));
TypeFailure(cx, "Missing type pushed %u: %s", i, TypeString(type));
}
}
}
#endif
/////////////////////////////////////////////////////////////////////
// JSObject
/////////////////////////////////////////////////////////////////////
@ -6762,8 +6796,12 @@ TypeScript::destroy()
}
/* static */ void
TypeScript::AddFreezeConstraints(JSContext *cx, HandleScript script)
TypeScript::AddFreezeConstraints(JSContext *cx, JSScript *script)
{
if (script->hasFreezeConstraints)
return;
script->hasFreezeConstraints = true;
/*
* Adding freeze constraints to a script ensures that code for the script
* will be recompiled any time any type set for stack values in the script

View File

@ -437,6 +437,8 @@ class TypeSet
: flags(0), objectSet(NULL), constraintList(NULL)
{}
TypeSet(Type type);
void print();
inline void sweep(JS::Zone *zone);
@ -468,7 +470,10 @@ class TypeSet
* Clone a type set into an arbitrary allocator. The result should not be
* modified further.
*/
const StackTypeSet *clone(LifoAlloc *alloc) const;
StackTypeSet *clone(LifoAlloc *alloc) const;
/* Join two type sets into a new set. The result should not be modified further. */
static StackTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
/*
* Add a type to this set, calling any constraint handlers if this is a new
@ -479,6 +484,12 @@ class TypeSet
/* Mark this type set as representing an own property or configured property. */
inline void setOwnProperty(JSContext *cx, bool configured);
/*
* Add an object to this set using the specified allocator, without
* triggering constraints.
*/
bool addObject(TypeObjectKey *key, LifoAlloc *alloc);
/*
* Iterate through the objects in this set. getObjectCount overapproximates
* in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
@ -542,6 +553,9 @@ class StackTypeSet : public TypeSet
{
public:
StackTypeSet() : TypeSet() {}
StackTypeSet(Type type) : TypeSet(type) {}
/*
* Make a type set with the specified debugging name, not embedded in
* another structure.
@ -577,6 +591,9 @@ class StackTypeSet : public TypeSet
/* Get any type tag which all values in this set must have. */
JSValueType getKnownTypeTag();
/* Whether any values in this set might have the specified type. */
bool mightBeType(JSValueType type);
bool isMagicArguments() { return getKnownTypeTag() == JSVAL_TYPE_MAGIC; }
/* Whether this value may be an object. */
@ -628,14 +645,6 @@ class StackTypeSet : public TypeSet
*/
bool knownNonStringPrimitive();
bool knownPrimitiveOrObject() {
TypeFlags flags = TYPE_FLAG_PRIMITIVE | TYPE_FLAG_ANYOBJECT;
if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK))
return false;
return true;
}
enum DoubleConversion {
/* All types in the set should use eager double conversion. */
AlwaysConvertToDoubles,
@ -1192,12 +1201,6 @@ class TypeScript
/* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
static inline StackTypeSet *SlotTypes(RawScript script, unsigned slot);
#ifdef DEBUG
/* Check that correct types were inferred for the values pushed by this bytecode. */
static void CheckBytecode(JSContext *cx, HandleScript script, jsbytecode *pc,
const js::Value *sp);
#endif
/* Get the default 'new' object for a given standard class, per the script's global. */
static inline TypeObject *StandardType(JSContext *cx, JSProtoKey kind);
@ -1242,7 +1245,7 @@ class TypeScript
static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg,
const js::Value &value);
static void AddFreezeConstraints(JSContext *cx, HandleScript script);
static void AddFreezeConstraints(JSContext *cx, JSScript *script);
static void Purge(JSContext *cx, HandleScript script);
static void Sweep(FreeOp *fop, RawScript script);

View File

@ -1746,6 +1746,34 @@ Property::Property(const Property &o)
{
}
inline bool
HasOperationOverflowed(JSScript *script, jsbytecode *pc)
{
types::TypeResult *result = script->types->dynamicList;
while (result) {
if (result->offset == uint32_t(pc - script->code)) {
if (result->type == types::Type::DoubleType())
return true;
}
result = result->next;
}
return false;
}
inline bool
IterationValuesMustBeStrings(JSScript *script)
{
// Return true if no custom non-string-producing iterators have been used
// in a 'for in' loop within the script.
types::TypeResult *result = script->types->dynamicList;
while (result) {
if (result->offset == UINT32_MAX)
return false;
result = result->next;
}
return true;
}
} } /* namespace js::types */
inline bool

View File

@ -1012,19 +1012,6 @@ js::IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval)
return js_IteratorNext(cx, iterobj, rval);
}
/*
* For bytecodes which push values and then fall through, make sure the
* types of the pushed values are consistent with type inference information.
*/
static inline void
TypeCheckNextBytecode(JSContext *cx, HandleScript script, unsigned n, const FrameRegs &regs)
{
#ifdef DEBUG
if (cx->typeInferenceEnabled() && n == GetBytecodeLength(regs.pc))
TypeScript::CheckBytecode(cx, script, regs.pc, regs.sp);
#endif
}
JS_NEVER_INLINE InterpretStatus
js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool useNewType)
{
@ -1247,7 +1234,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool
JS_ASSERT(js_CodeSpec[op].length == 1);
len = 1;
advance_pc:
TypeCheckNextBytecode(cx, script, len, regs);
js::gc::MaybeVerifyBarriers(cx);
regs.pc += len;
op = (JSOp) *regs.pc;
@ -3717,6 +3703,12 @@ js::SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleV
return SetObjectElementOperation(cx, obj, id, value, strict, script, pc);
}
bool
js::InitElementArray(JSContext *cx, jsbytecode *pc, HandleObject obj, uint32_t index, HandleValue value)
{
return InitArrayElemOperation(cx, pc, obj, index, value);
}
bool
js::AddValues(JSContext *cx, HandleScript script, jsbytecode *pc,
MutableHandleValue lhs, MutableHandleValue rhs,

View File

@ -372,6 +372,10 @@ bool
SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
JSBool strict, HandleScript script, jsbytecode *pc);
bool
InitElementArray(JSContext *cx, jsbytecode *pc,
HandleObject obj, uint32_t index, HandleValue value);
bool
AddValues(JSContext *cx, HandleScript script, jsbytecode *pc,
MutableHandleValue lhs, MutableHandleValue rhs,

View File

@ -892,7 +892,7 @@ SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, con
RootedScript script(cx, maybeScript);
types::TypeScript::MonitorAssign(cx, obj, id);
if (obj->isArray() && JSID_IS_INT(id)) {
if (obj->isNative() && JSID_IS_INT(id)) {
uint32_t length = obj->getDenseInitializedLength();
int32_t i = JSID_TO_INT(id);
if ((uint32_t)i >= length) {

View File

@ -308,6 +308,8 @@ js_DumpPCCounts(JSContext *cx, HandleScript script, js::Sprinter *sp)
Sprint(sp, "IonScript [%lu blocks]:\n", ionCounts->numBlocks());
for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
const ion::IonBlockCounts &block = ionCounts->block(i);
if (block.hitCount() < 10)
continue;
Sprint(sp, "BB #%lu [%05u]", block.id(), block.offset());
for (size_t j = 0; j < block.numSuccessors(); j++)
Sprint(sp, " -> #%lu", block.successor(j));

View File

@ -995,7 +995,7 @@ mjit::CanMethodJIT(JSContext *cx, JSScript *script, jsbytecode *pc,
return Compile_Abort;
#ifdef JS_ION
if (ion::IsBaselineEnabled(cx))
if (ion::IsBaselineEnabled(cx) || ion::IsEnabled(cx))
return Compile_Abort;
#endif

View File

@ -19,6 +19,8 @@
#include "jsfuninlines.h"
#include "jstypedarrayinlines.h"
#include "ion/BaselineJIT.h"
#include "vm/BooleanObject-inl.h"
#include "vm/NumberObject-inl.h"
#include "vm/RegExpObject-inl.h"
@ -415,7 +417,9 @@ intrinsic_ParallelTestsShouldPass(JSContext *cx, unsigned argc, Value *vp)
CallArgs args = CallArgsFromVp(argc, vp);
#if defined(JS_THREADSAFE) && defined(JS_ION)
args.rval().setBoolean(ion::IsEnabled(cx) &&
!ion::js_IonOptions.eagerCompilation);
ion::IsBaselineEnabled(cx) &&
!ion::js_IonOptions.eagerCompilation &&
ion::js_IonOptions.baselineUsesBeforeCompile != 0);
#else
args.rval().setBoolean(false);
#endif

View File

@ -227,12 +227,11 @@ class AbstractFramePtr
{
uintptr_t ptr_;
protected:
public:
AbstractFramePtr()
: ptr_(0)
{}
public:
AbstractFramePtr(StackFrame *fp)
: ptr_(fp ? uintptr_t(fp) | 0x1 : 0)
{

View File

@ -13,15 +13,16 @@
using namespace mozilla;
using namespace xpc;
using namespace JS;
XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
JSContext* cx /* = nullptr */,
JSObject* obj /* = nullptr */,
JSObject* funobj /* = nullptr */,
jsid name /* = JSID_VOID */,
unsigned argc /* = NO_ARGS */,
jsval *argv /* = nullptr */,
jsval *rval /* = nullptr */)
JSContext* cx /* = GetDefaultJSContext() */,
HandleObject obj /* = nullptr */,
HandleObject funobj /* = nullptr */,
HandleId name /* = JSID_VOID */,
unsigned argc /* = NO_ARGS */,
jsval *argv /* = nullptr */,
jsval *rval /* = nullptr */)
: mState(INIT_FAILED),
mXPC(nsXPConnect::GetXPConnect()),
mXPCContext(nullptr),
@ -29,12 +30,13 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
mContextPopRequired(false),
mDestroyJSContextInDestructor(false),
mCallerLanguage(callerLanguage),
mScopeForNewJSObjects(xpc_GetSafeJSContext()),
mFlattenedJSObject(xpc_GetSafeJSContext()),
mScopeForNewJSObjects(cx),
mFlattenedJSObject(cx),
mWrapper(nullptr),
mTearOff(nullptr),
mName(xpc_GetSafeJSContext())
mName(cx)
{
MOZ_ASSERT(cx);
Init(callerLanguage, callerLanguage == NATIVE_CALLER, obj, funobj,
INIT_SHOULD_LOOKUP_WRAPPER, name, argc, argv, rval);
}
@ -42,8 +44,8 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
JSContext* cx,
JSBool callBeginRequest,
JSObject* obj,
JSObject* flattenedJSObject,
HandleObject obj,
HandleObject flattenedJSObject,
XPCWrappedNative* wrapper,
XPCWrappedNativeTearOff* tearOff)
: mState(INIT_FAILED),
@ -53,61 +55,58 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
mContextPopRequired(false),
mDestroyJSContextInDestructor(false),
mCallerLanguage(callerLanguage),
mScopeForNewJSObjects(xpc_GetSafeJSContext()),
mFlattenedJSObject(xpc_GetSafeJSContext(), flattenedJSObject),
mScopeForNewJSObjects(cx),
mFlattenedJSObject(cx, flattenedJSObject),
mWrapper(wrapper),
mTearOff(tearOff),
mName(xpc_GetSafeJSContext())
mName(cx)
{
Init(callerLanguage, callBeginRequest, obj, nullptr,
WRAPPER_PASSED_TO_CONSTRUCTOR, JSID_VOID, NO_ARGS,
MOZ_ASSERT(cx);
Init(callerLanguage, callBeginRequest, obj, NullPtr(),
WRAPPER_PASSED_TO_CONSTRUCTOR, JSID_VOIDHANDLE, NO_ARGS,
nullptr, nullptr);
}
#define IS_TEAROFF_CLASS(clazz) ((clazz) == &XPC_WN_Tearoff_JSClass)
// static
JSContext *
XPCCallContext::GetDefaultJSContext()
{
// This is slightly questionable. If called without an explicit
// JSContext (generally a call to a wrappedJS) we will use the JSContext
// on the top of the JSContext stack - if there is one - *before*
// falling back on the safe JSContext.
// This is good AND bad because it makes calls from JS -> native -> JS
// have JS stack 'continuity' for purposes of stack traces etc.
// Note: this *is* what the pre-XPCCallContext xpconnect did too.
XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
JSContext *topJSContext = stack->Peek();
return topJSContext ? topJSContext : stack->GetSafeJSContext();
}
void
XPCCallContext::Init(XPCContext::LangType callerLanguage,
JSBool callBeginRequest,
JSObject* obj,
JSObject* funobj,
HandleObject obj,
HandleObject funobj,
WrapperInitOptions wrapperInitOptions,
jsid name,
HandleId name,
unsigned argc,
jsval *argv,
jsval *rval)
{
NS_ASSERTION(mJSContext, "No JSContext supplied to XPCCallContext");
if (!mXPC)
return;
XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
if (!stack) {
// If we don't have a stack we're probably in shutdown.
mJSContext = nullptr;
return;
}
JSContext *topJSContext = stack->Peek();
if (!mJSContext) {
// This is slightly questionable. If called without an explicit
// JSContext (generally a call to a wrappedJS) we will use the JSContext
// on the top of the JSContext stack - if there is one - *before*
// falling back on the safe JSContext.
// This is good AND bad because it makes calls from JS -> native -> JS
// have JS stack 'continuity' for purposes of stack traces etc.
// Note: this *is* what the pre-XPCCallContext xpconnect did too.
if (topJSContext) {
mJSContext = topJSContext;
} else {
mJSContext = stack->GetSafeJSContext();
if (!mJSContext)
return;
}
}
if (topJSContext != mJSContext) {
if (!stack->Push(mJSContext)) {
NS_ERROR("bad!");
@ -204,7 +203,7 @@ XPCCallContext::SetName(jsid name)
if (mTearOff) {
mSet = nullptr;
mInterface = mTearOff->GetInterface();
mMember = mInterface->FindMember(name);
mMember = mInterface->FindMember(mName);
mStaticMemberIsLocal = true;
if (mMember && !mMember->IsConstant())
mMethodIndex = mMember->GetIndex();
@ -212,7 +211,7 @@ XPCCallContext::SetName(jsid name)
mSet = mWrapper ? mWrapper->GetSet() : nullptr;
if (mSet &&
mSet->FindMember(name, &mMember, &mInterface,
mSet->FindMember(mName, &mMember, &mInterface,
mWrapper->HasProto() ?
mWrapper->GetProto()->GetSet() :
nullptr,
@ -459,9 +458,8 @@ XPCLazyCallContext::AssertContextIsTopOfStack(JSContext* cx)
#endif
XPCWrappedNative*
XPCCallContext::UnwrapThisIfAllowed(JSObject *object, JSObject *fun, unsigned argc)
XPCCallContext::UnwrapThisIfAllowed(HandleObject obj, HandleObject fun, unsigned argc)
{
JS::Rooted<JSObject *> obj(mJSContext, object);
// We should only get here for objects that aren't safe to unwrap.
MOZ_ASSERT(!js::CheckedUnwrap(obj));
MOZ_ASSERT(js::IsObjectInContextCompartment(obj, mJSContext));
@ -482,7 +480,7 @@ XPCCallContext::UnwrapThisIfAllowed(JSObject *object, JSObject *fun, unsigned ar
// First, get the XPCWN out of the underlying object. We should have a wrapper
// here, potentially an outer window proxy, and then an XPCWN.
MOZ_ASSERT(js::IsWrapper(obj));
JSObject *unwrapped = js::UncheckedUnwrap(obj, /* stopAtOuter = */ false);
RootedObject unwrapped(mJSContext, js::UncheckedUnwrap(obj, /* stopAtOuter = */ false));
MOZ_ASSERT(unwrapped == JS_ObjectToInnerObject(mJSContext, js::Wrapper::wrappedObject(obj)));
// Make sure we have an XPCWN, and grab it.

View File

@ -3190,7 +3190,8 @@ bool BindPropertyOp(JSContext *cx, Op &op, PropertyDescriptor *desc, HandleId id
// We have an actual property op. For getters, we use 0
// args, for setters we use 1 arg.
uint32_t args = (attrFlag == JSPROP_GETTER) ? 0 : 1;
func = GeneratePropertyOp(cx, desc->obj, id, args, op);
RootedObject obj(cx, desc->obj);
func = GeneratePropertyOp(cx, obj, id, args, op);
if (!func)
return false;
}

View File

@ -29,6 +29,7 @@
using namespace xpc;
using namespace mozilla;
using namespace mozilla::dom;
using namespace JS;
//#define STRICT_CHECK_OF_UNICODE
#ifdef STRICT_CHECK_OF_UNICODE
@ -169,7 +170,7 @@ XPCConvert::NativeData2JS(XPCLazyCallContext& lccx, jsval* d, const void* s,
nsID* iid2 = *((nsID**)s);
if (!iid2)
break;
JS::RootedObject scope(cx, lccx.GetScopeForNewJSObjects());
RootedObject scope(cx, lccx.GetScopeForNewJSObjects());
JSObject* obj;
if (!(obj = xpc_NewIDObject(cx, scope, *iid2)))
return false;
@ -369,7 +370,7 @@ bool ConvertToPrimitive(JSContext *cx, const JS::Value& v, T *retval)
// static
JSBool
XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s,
XPCConvert::JSData2Native(JSContext* cx, void* d, HandleValue s,
const nsXPTType& type,
JSBool useAllocator, const nsID* iid,
nsresult* pErr)
@ -754,8 +755,8 @@ XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s,
return false;
}
return JSObject2NativeInterface(cx, (void**)d, &s.toObject(), iid,
nullptr, pErr);
RootedObject src(cx, &s.toObject());
return JSObject2NativeInterface(cx, (void**)d, src, iid, nullptr, pErr);
}
default:
NS_ERROR("bad type");
@ -765,7 +766,7 @@ XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s,
}
inline JSBool
CreateHolderIfNeeded(XPCCallContext& ccx, JSObject* obj, jsval* d,
CreateHolderIfNeeded(XPCCallContext& ccx, HandleObject obj, jsval* d,
nsIXPConnectJSObjectHolder** dest)
{
if (dest) {
@ -830,7 +831,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
nsWrapperCache *cache = aHelper.GetWrapperCache();
bool tryConstructSlimWrapper = false;
JS::RootedObject flat(cx);
RootedObject flat(cx);
if (cache) {
flat = cache->GetWrapper();
if (cache->IsDOMBinding()) {
@ -874,7 +875,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
if (!ccx.IsValid())
return false;
jsval slim;
RootedValue slim(cx);
if (ConstructSlimWrapper(ccx, aHelper, xpcscope, &slim)) {
*d = slim;
return true;
@ -975,7 +976,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
// The call to wrap here handles both cross-compartment and same-compartment
// security wrappers.
JSObject *original = flat;
RootedObject original(cx, flat);
if (!JS_WrapObject(ccx, flat.address()))
return false;
@ -1006,7 +1007,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
// static
JSBool
XPCConvert::JSObject2NativeInterface(JSContext* cx,
void** dest, JSObject* src,
void** dest, HandleObject src,
const nsID* iid,
nsISupports* aOuter,
nsresult* pErr)
@ -1153,23 +1154,24 @@ public:
private:
JSContext * const mContext;
JS::AutoValueRooter tvr;
AutoValueRooter tvr;
};
// static
nsresult
XPCConvert::JSValToXPCException(XPCCallContext& ccx,
jsval s,
jsval sArg,
const char* ifaceName,
const char* methodName,
nsIException** exceptn)
{
JSContext* cx = ccx.GetJSContext();
RootedValue s(cx, sArg);
AutoExceptionRestorer aer(cx, s);
if (!JSVAL_IS_PRIMITIVE(s)) {
// we have a JSObject
JSObject* obj = JSVAL_TO_OBJECT(s);
RootedObject obj(cx, JSVAL_TO_OBJECT(s));
if (!obj) {
NS_ERROR("when is an object not an object?");
@ -1255,14 +1257,14 @@ XPCConvert::JSValToXPCException(XPCCallContext& ccx,
return ConstructException(NS_ERROR_XPC_JS_THREW_JS_OBJECT,
strBytes.ptr(), ifaceName, methodName,
nullptr, exceptn, cx, &s);
nullptr, exceptn, cx, s.address());
}
}
if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) {
return ConstructException(NS_ERROR_XPC_JS_THREW_NULL,
nullptr, ifaceName, methodName, nullptr,
exceptn, cx, &s);
exceptn, cx, s.address());
}
if (JSVAL_IS_NUMBER(s)) {
@ -1293,7 +1295,7 @@ XPCConvert::JSValToXPCException(XPCCallContext& ccx,
if (isResult)
return ConstructException(rv, nullptr, ifaceName, methodName,
nullptr, exceptn, cx, &s);
nullptr, exceptn, cx, s.address());
else {
// XXX all this nsISupportsDouble code seems a little redundant
// now that we're storing the jsval in the exception...
@ -1307,7 +1309,7 @@ XPCConvert::JSValToXPCException(XPCCallContext& ccx,
return NS_ERROR_FAILURE;
data->SetData(number);
rv = ConstructException(NS_ERROR_XPC_JS_THREW_NUMBER, nullptr,
ifaceName, methodName, data, exceptn, cx, &s);
ifaceName, methodName, data, exceptn, cx, s.address());
NS_RELEASE(data);
return rv;
}
@ -1322,7 +1324,7 @@ XPCConvert::JSValToXPCException(XPCCallContext& ccx,
if (!!strBytes) {
return ConstructException(NS_ERROR_XPC_JS_THREW_STRING,
strBytes.ptr(), ifaceName, methodName,
nullptr, exceptn, cx, &s);
nullptr, exceptn, cx, s.address());
}
}
return NS_ERROR_FAILURE;
@ -1660,7 +1662,7 @@ XPCConvert::JSArray2Native(JSContext* cx, void** d, JS::Value s,
return false;
}
JSObject* jsarray = &s.toObject();
RootedObject jsarray(cx, &s.toObject());
// If this is a typed array, then try a fast conversion with memcpy.
if (JS_IsTypedArrayObject(jsarray)) {
@ -1683,22 +1685,22 @@ XPCConvert::JSArray2Native(JSContext* cx, void** d, JS::Value s,
if (pErr)
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
#define POPULATE(_mode, _t) \
PR_BEGIN_MACRO \
cleanupMode = _mode; \
size_t max = UINT32_MAX / sizeof(_t); \
if (count > max || \
#define POPULATE(_mode, _t) \
PR_BEGIN_MACRO \
cleanupMode = _mode; \
size_t max = UINT32_MAX / sizeof(_t); \
if (count > max || \
nullptr == (array = nsMemory::Alloc(count * sizeof(_t)))) { \
if (pErr) \
*pErr = NS_ERROR_OUT_OF_MEMORY; \
goto failure; \
} \
for (initedCount = 0; initedCount < count; initedCount++) { \
if (!JS_GetElement(cx, jsarray, initedCount, &current) || \
!JSData2Native(cx, ((_t*)array)+initedCount, current, type, \
true, iid, pErr)) \
goto failure; \
} \
if (pErr) \
*pErr = NS_ERROR_OUT_OF_MEMORY; \
goto failure; \
} \
for (initedCount = 0; initedCount < count; initedCount++) { \
if (!JS_GetElement(cx, jsarray, initedCount, current.address()) || \
!JSData2Native(cx, ((_t*)array)+initedCount, current, type, \
true, iid, pErr)) \
goto failure; \
} \
PR_END_MACRO
// No Action, FRee memory, RElease object
@ -1708,7 +1710,7 @@ XPCConvert::JSArray2Native(JSContext* cx, void** d, JS::Value s,
void *array = nullptr;
uint32_t initedCount;
jsval current;
RootedValue current(cx);
// XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
// XXX make extra space at end of char* and wchar* and null termintate

View File

@ -259,7 +259,7 @@ XPCCallContext::GetResolveName() const
}
inline jsid
XPCCallContext::SetResolveName(jsid name)
XPCCallContext::SetResolveName(JS::HandleId name)
{
CHECK_STATE(HAVE_CONTEXT);
return XPCJSRuntime::Get()->SetResolveName(name);

View File

@ -409,8 +409,8 @@ nsJSIID::NewResolve(nsIXPConnectWrappedNative *wrapper,
XPCNativeMember* member = iface->FindMember(id);
if (member && member->IsConstant()) {
jsval val;
if (!member->GetConstantValue(ccx, iface, &val))
RootedValue val(cx);
if (!member->GetConstantValue(ccx, iface, val.address()))
return NS_ERROR_OUT_OF_MEMORY;
*objp = obj;
@ -837,9 +837,8 @@ nsJSCID::Construct(nsIXPConnectWrappedNative *wrapper,
return NS_ERROR_FAILURE;
// 'push' a call context and call on it
XPCCallContext ccx(JS_CALLER, cx, obj, nullptr,
rt->GetStringID(XPCJSRuntime::IDX_CREATE_INSTANCE),
argc, argv, vp);
RootedId name(cx, rt->GetStringID(XPCJSRuntime::IDX_CREATE_INSTANCE));
XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), name, argc, argv, vp);
*_retval = XPCWrappedNative::CallMethod(ccx);
return NS_OK;
@ -887,7 +886,7 @@ nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper,
JSObject *
xpc_NewIDObject(JSContext *cx, HandleObject jsobj, const nsID& aID)
{
JSObject *obj = nullptr;
RootedObject obj(cx);
nsCOMPtr<nsIJSID> iid =
dont_AddRef(static_cast<nsIJSID*>(nsJSID::NewID(aID)));
@ -900,7 +899,7 @@ xpc_NewIDObject(JSContext *cx, HandleObject jsobj, const nsID& aID)
NS_GET_IID(nsIJSID),
getter_AddRefs(holder));
if (NS_SUCCEEDED(rv) && holder) {
holder->GetJSObject(&obj);
holder->GetJSObject(obj.address());
}
}
}

View File

@ -43,6 +43,7 @@
using namespace mozilla;
using namespace xpc;
using namespace JS;
/***************************************************************************/
@ -2232,7 +2233,8 @@ class XPCJSRuntimeStats : public JS::RuntimeStats
JSCompartment *comp = js::GetAnyCompartmentInZone(zone);
xpc::ZoneStatsExtras *extras = new xpc::ZoneStatsExtras;
extras->pathPrefix.AssignLiteral("explicit/js-non-window/zones/");
if (JSObject *global = JS_GetGlobalForCompartmentOrNull(cx, comp)) {
RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, comp));
if (global) {
// Need to enter the compartment, otherwise GetNativeOfWrapper()
// might crash.
JSAutoCompartment ac(cx, global);
@ -2262,7 +2264,8 @@ class XPCJSRuntimeStats : public JS::RuntimeStats
nsXPConnect *xpc = nsXPConnect::GetXPConnect();
JSContext *cx = xpc->GetSafeJSContext();
bool needZone = true;
if (JSObject *global = JS_GetGlobalForCompartmentOrNull(cx, c)) {
RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, c));
if (global) {
// Need to enter the compartment, otherwise GetNativeOfWrapper()
// might crash.
JSAutoCompartment ac(cx, global);
@ -2495,13 +2498,14 @@ CompartmentNameCallback(JSRuntime *rt, JSCompartment *comp,
bool XPCJSRuntime::gXBLScopesEnabled;
static bool
PreserveWrapper(JSContext *cx, JSObject *obj)
PreserveWrapper(JSContext *cx, JSObject *objArg)
{
MOZ_ASSERT(cx);
MOZ_ASSERT(obj);
MOZ_ASSERT(js::GetObjectClass(obj)->ext.isWrappedNative ||
mozilla::dom::IsDOMObject(obj));
MOZ_ASSERT(objArg);
MOZ_ASSERT(js::GetObjectClass(objArg)->ext.isWrappedNative ||
mozilla::dom::IsDOMObject(objArg));
RootedObject obj(cx, objArg);
XPCCallContext ccx(NATIVE_CALLER, cx);
if (!ccx.IsValid())
return false;
@ -2812,8 +2816,9 @@ XPCJSRuntime::OnJSContextNew(JSContext *cx)
// Scope the JSAutoRequest so it goes out of scope before calling
// mozilla::dom::binding::DefineStaticJSVals.
JSAutoRequest ar(cx);
RootedString str(cx);
for (unsigned i = 0; i < IDX_TOTAL_COUNT; i++) {
JSString* str = JS_InternString(cx, mStrings[i]);
str = JS_InternString(cx, mStrings[i]);
if (!str || !JS_ValueToId(cx, STRING_TO_JSVAL(str), &mStrIDs[i])) {
mStrIDs[0] = JSID_VOID;
return false;
@ -3005,12 +3010,12 @@ JSObject *
XPCJSRuntime::GetJunkScope()
{
if (!mJunkScope) {
JS::Value v;
SafeAutoJSContext cx;
SandboxOptions options(cx);
options.sandboxName.AssignASCII("XPConnect Junk Compartment");
JSAutoRequest ac(cx);
nsresult rv = xpc_CreateSandboxObject(cx, &v,
RootedValue v(cx);
nsresult rv = xpc_CreateSandboxObject(cx, v.address(),
nsContentUtils::GetSystemPrincipal(),
options);

View File

@ -650,14 +650,15 @@ public:
}
}
void Reparent(JSContext *aCx, JSObject *aNewInner) {
void Reparent(JSContext *aCx, JSObject *aNewInnerArg) {
JS::RootedObject aNewInner(aCx, aNewInnerArg);
for (Map::Enum e(mTable); !e.empty(); e.popFront()) {
/*
* We reparent wrappers that have as their parent an inner window
* whose outer has the new inner window as its current inner.
*/
JSObject *parent = JS_GetParent(e.front().value);
JSObject *outer = JS_ObjectToOuterObject(aCx, parent);
JS::RootedObject parent(aCx, JS_GetParent(e.front().value));
JS::RootedObject outer(aCx, JS_ObjectToOuterObject(aCx, parent));
if (outer) {
JSObject *inner = JS_ObjectToInnerObject(aCx, outer);
if (inner == aNewInner && inner != parent)

View File

@ -14,6 +14,7 @@
#include "mozilla/dom/BindingUtils.h"
using namespace mozilla;
using namespace JS;
extern const char* xpc_qsStringTable;
@ -99,7 +100,7 @@ PointerHolderClass = {
};
JSBool
xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, unsigned flags,
xpc_qsDefineQuickStubs(JSContext *cx, JSObject *protoArg, unsigned flags,
uint32_t ifacec, const nsIID **interfaces,
uint32_t tableSize, const xpc_qsHashEntry *table,
const xpc_qsPropertySpec *propspecs,
@ -114,6 +115,7 @@ xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, unsigned flags,
* searching the interfaces forward. Here, definitions toward the
* front of 'interfaces' overwrite those toward the back.
*/
RootedObject proto(cx, protoArg);
for (uint32_t i = ifacec; i-- != 0;) {
const nsID &iid = *interfaces[i];
const xpc_qsHashEntry *entry =
@ -222,7 +224,7 @@ GetMethodInfo(JSContext *cx, jsval *vp, const char **ifaceNamep, jsid *memberIdp
static bool
ThrowCallFailed(JSContext *cx, nsresult rv,
const char *ifaceName, jsid memberId, const char *memberName)
const char *ifaceName, HandleId memberId, const char *memberName)
{
/* Only one of memberId or memberName should be given. */
MOZ_ASSERT(JSID_IS_VOID(memberId) != !memberName);
@ -273,17 +275,19 @@ ThrowCallFailed(JSContext *cx, nsresult rv,
JSBool
xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *obj,
jsid memberId)
jsid memberIdArg)
{
RootedId memberId(cx, memberIdArg);
const char *ifaceName;
GetMemberInfo(obj, memberId, &ifaceName);
return ThrowCallFailed(cx, rv, ifaceName, memberId, NULL);
}
JSBool
xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *obj,
xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *objArg,
const char* memberName)
{
RootedObject obj(cx, objArg);
JSString *str = JS_InternString(cx, memberName);
if (!str) {
return false;
@ -304,8 +308,8 @@ JSBool
xpc_qsThrowMethodFailed(JSContext *cx, nsresult rv, jsval *vp)
{
const char *ifaceName;
jsid memberId;
GetMethodInfo(cx, vp, &ifaceName, &memberId);
RootedId memberId(cx);
GetMethodInfo(cx, vp, &ifaceName, memberId.address());
return ThrowCallFailed(cx, rv, ifaceName, memberId, NULL);
}
@ -321,7 +325,7 @@ xpc_qsThrowMethodFailedWithDetails(JSContext *cx, nsresult rv,
const char *ifaceName,
const char *memberName)
{
return ThrowCallFailed(cx, rv, ifaceName, JSID_VOID, memberName);
return ThrowCallFailed(cx, rv, ifaceName, JSID_VOIDHANDLE, memberName);
}
static void
@ -386,8 +390,9 @@ xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv,
void
xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv,
JSObject *obj, const char* propName)
JSObject *objArg, const char* propName)
{
RootedObject obj(cx, objArg);
JSString *str = JS_InternString(cx, propName);
if (!str) {
return;
@ -494,7 +499,7 @@ xpc_qsAUTF8String::xpc_qsAUTF8String(JSContext *cx, jsval v, jsval *pval)
static nsresult
getNative(nsISupports *idobj,
QITableEntry* entries,
JSObject *obj,
HandleObject obj,
const nsIID &iid,
void **ppThis,
nsISupports **pThisRef,
@ -527,8 +532,9 @@ getNativeFromWrapper(JSContext *cx,
nsISupports **pThisRef,
jsval *vp)
{
RootedObject obj(cx, wrapper->GetFlatJSObject());
return getNative(wrapper->GetIdentityObject(), wrapper->GetOffsets(),
wrapper->GetFlatJSObject(), iid, ppThis, pThisRef, vp);
obj, iid, ppThis, pThisRef, vp);
}
@ -595,7 +601,7 @@ getWrapper(JSContext *cx,
nsresult
castNative(JSContext *cx,
XPCWrappedNative *wrapper,
JSObject *cur,
JSObject *curArg,
XPCWrappedNativeTearOff *tearoff,
const nsIID &iid,
void **ppThis,
@ -603,6 +609,7 @@ castNative(JSContext *cx,
jsval *vp,
XPCLazyCallContext *lccx)
{
RootedObject cur(cx, curArg);
if (wrapper) {
nsresult rv = getNativeFromWrapper(cx,wrapper, iid, ppThis, pThisRef,
vp);
@ -653,9 +660,9 @@ xpc_qsUnwrapThisFromCcxImpl(XPCCallContext &ccx,
if (!native)
return xpc_qsThrow(ccx.GetJSContext(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN);
RootedObject obj(ccx, ccx.GetFlattenedJSObject());
nsresult rv = getNative(native, GetOffsets(native, ccx.GetProto()),
ccx.GetFlattenedJSObject(), iid, ppThis, pThisRef,
vp);
obj, iid, ppThis, pThisRef, vp);
if (NS_FAILED(rv))
return xpc_qsThrow(ccx.GetJSContext(), rv);
return true;
@ -670,7 +677,7 @@ xpc_qsUnwrapArgImpl(JSContext *cx,
jsval *vp)
{
nsresult rv;
JSObject *src = xpc_qsUnwrapObj(v, ppArgRef, &rv);
RootedObject src(cx, xpc_qsUnwrapObj(v, ppArgRef, &rv));
if (!src) {
*ppArg = nullptr;

View File

@ -665,7 +665,7 @@ PropertyOpForwarder(JSContext *cx, unsigned argc, jsval *vp)
JS::CallArgs args = CallArgsFromVp(argc, vp);
JSObject *callee = &args.callee();
JS::RootedObject callee(cx, &args.callee());
JS::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
if (!obj)
return false;
@ -677,7 +677,7 @@ PropertyOpForwarder(JSContext *cx, unsigned argc, jsval *vp)
v = js::GetFunctionNativeReserved(callee, 1);
jsval argval = (argc > 0) ? args[0] : JSVAL_VOID;
JS::RootedValue argval(cx, (argc > 0) ? args.get(0) : JSVAL_VOID);
JS::RootedId id(cx);
if (!JS_ValueToId(cx, v, id.address()))
return false;
@ -689,7 +689,7 @@ extern JSClass PointerHolderClass;
template<typename Op>
JSObject *
GeneratePropertyOp(JSContext *cx, JSObject *obj, jsid id, unsigned argc, Op pop)
GeneratePropertyOp(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned argc, Op pop)
{
// The JS engine provides two reserved slots on function objects for
// XPConnect to use. Use them to stick the necessary info here.
@ -698,9 +698,7 @@ GeneratePropertyOp(JSContext *cx, JSObject *obj, jsid id, unsigned argc, Op pop)
if (!fun)
return nullptr;
JSObject *funobj = JS_GetFunctionObject(fun);
JS::AutoObjectRooter tvr(cx, funobj);
JS::RootedObject funobj(cx, JS_GetFunctionObject(fun));
// Unfortunately, we cannot guarantee that Op is aligned. Use a
// second object to work around this.

View File

@ -11,6 +11,8 @@
#include "jsfriendapi.h"
using namespace JS;
NS_IMPL_CLASSINFO(XPCVariant, NULL, 0, XPCVARIANT_CID)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XPCVariant)
NS_INTERFACE_MAP_ENTRY(XPCVariant)
@ -149,7 +151,7 @@ private:
static const Type StateTable[tTypeCount][tTypeCount-1];
public:
static JSBool GetTypeForArray(JSContext* cx, JSObject* array,
static JSBool GetTypeForArray(JSContext* cx, HandleObject array,
uint32_t length,
nsXPTType* resultType, nsID* resultID);
};
@ -174,16 +176,17 @@ XPCArrayHomogenizer::StateTable[tTypeCount][tTypeCount-1] = {
// static
JSBool
XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, JSObject* array,
XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array,
uint32_t length,
nsXPTType* resultType, nsID* resultID)
{
Type state = tUnk;
Type type;
RootedValue val(cx);
RootedObject jsobj(cx);
for (uint32_t i = 0; i < length; i++) {
JS::Value val;
if (!JS_GetElement(cx, array, i, &val))
if (!JS_GetElement(cx, array, i, val.address()))
return false;
if (val.isInt32()) {
@ -192,7 +195,7 @@ XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, JSObject* array,
type = tDbl;
} else if (val.isBoolean()) {
type = tBool;
} else if (val.isUndefined()) {
} else if (val.isUndefined()) {
state = tVar;
break;
} else if (val.isNull()) {
@ -201,7 +204,7 @@ XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, JSObject* array,
type = tStr;
} else {
NS_ASSERTION(val.isObject(), "invalid type of jsval!");
JSObject* jsobj = &val.toObject();
jsobj = &val.toObject();
if (JS_IsArrayObject(cx, jsobj))
type = tArr;
else if (xpc_JSObjectIsID(cx, jsobj))
@ -267,7 +270,7 @@ JSBool XPCVariant::InitializeData(JSContext* cx)
{
JS_CHECK_RECURSION(cx, return false);
JS::Value val = GetJSVal();
RootedValue val(cx, GetJSVal());
if (val.isInt32())
return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, val.toInt32()));
@ -309,7 +312,7 @@ JSBool XPCVariant::InitializeData(JSContext* cx)
// leaving only JSObject...
NS_ASSERTION(val.isObject(), "invalid type of jsval!");
JSObject* jsobj = &val.toObject();
RootedObject jsobj(cx, &val.toObject());
// Let's see if it is a xpcJSID.
@ -378,16 +381,16 @@ XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx,
if (NS_FAILED(variant->GetDataType(&type)))
return false;
jsval realVal;
nsresult rv = variant->GetAsJSVal(&realVal);
JSContext *cx = lccx.GetJSContext();
RootedValue realVal(cx);
nsresult rv = variant->GetAsJSVal(realVal.address());
if (NS_SUCCEEDED(rv) &&
(JSVAL_IS_PRIMITIVE(realVal) ||
type == nsIDataType::VTYPE_ARRAY ||
type == nsIDataType::VTYPE_EMPTY_ARRAY ||
type == nsIDataType::VTYPE_ID)) {
JSContext *cx = lccx.GetJSContext();
if (!JS_WrapValue(cx, &realVal))
if (!JS_WrapValue(cx, realVal.address()))
return false;
*pJSVal = realVal;
return true;
@ -399,8 +402,7 @@ XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx,
type == nsIDataType::VTYPE_INTERFACE_IS,
"Weird variant");
JSContext *cx = lccx.GetJSContext();
if (!JS_WrapValue(cx, &realVal))
if (!JS_WrapValue(cx, realVal.address()))
return false;
*pJSVal = realVal;
return true;
@ -425,7 +427,6 @@ XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx,
xpctvar.flags = 0;
JSBool success;
JSContext* cx = lccx.GetJSContext();
NS_ABORT_IF_FALSE(js::IsObjectInContextCompartment(lccx.GetScopeForNewJSObjects(), cx),
"bad scope for new JSObjects");

View File

@ -406,8 +406,8 @@ nsXPCWrappedJSClass::BuildPropertyEnumerator(XPCCallContext& ccx,
return NS_ERROR_FAILURE;
}
jsval jsvalName;
if (!JS_IdToValue(cx, idName, &jsvalName))
RootedValue jsvalName(cx);
if (!JS_IdToValue(cx, idName, jsvalName.address()))
return NS_ERROR_FAILURE;
JSString* name = JS_ValueToString(cx, jsvalName);
@ -625,6 +625,8 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
}
JSContext *context = GetContextFromObject(self->GetJSObject());
if (!context)
context = XPCCallContext::GetDefaultJSContext();
XPCCallContext ccx(NATIVE_CALLER, context);
if (!ccx.IsValid()) {
*aInstancePtr = nullptr;
@ -1142,6 +1144,8 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
// convert natives to JSObjects, but we do NOT plan to pass those JSObjects
// to our real callee.
JSContext *context = GetContextFromObject(wrapper->GetJSObject());
if (!context)
context = XPCCallContext::GetDefaultJSContext();
XPCCallContext ccx(NATIVE_CALLER, context);
if (!ccx.IsValid())
return retval;

View File

@ -3616,7 +3616,7 @@ static uint32_t sSlimWrappers;
JSBool
ConstructSlimWrapper(XPCCallContext &ccx,
xpcObjectHelper &aHelper,
XPCWrappedNativeScope* xpcScope, jsval *rval)
XPCWrappedNativeScope* xpcScope, MutableHandleValue rval)
{
nsISupports *identityObj = aHelper.GetCanonical();
nsXPCClassInfo *classInfoHelper = aHelper.GetXPCClassInfo();
@ -3672,7 +3672,7 @@ ConstructSlimWrapper(XPCCallContext &ccx,
nsWrapperCache *cache = aHelper.GetWrapperCache();
JSObject* wrapper = cache->GetWrapper();
if (wrapper) {
*rval = OBJECT_TO_JSVAL(wrapper);
rval.setObject(*wrapper);
return true;
}
@ -3709,7 +3709,7 @@ ConstructSlimWrapper(XPCCallContext &ccx,
SLIM_LOG(("+++++ %i created slim wrapper (%p, %p, %p)\n", ++sSlimWrappers,
wrapper, p, xpcScope));
*rval = OBJECT_TO_JSVAL(wrapper);
rval.setObject(*wrapper);
return true;
}

View File

@ -77,7 +77,7 @@ ToStringGuts(XPCCallContext& ccx)
static JSBool
XPC_WN_Shared_ToString(JSContext *cx, unsigned argc, jsval *vp)
{
JSObject *obj = JS_THIS_OBJECT(cx, vp);
RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
if (!obj)
return false;
@ -93,7 +93,7 @@ XPC_WN_Shared_ToString(JSContext *cx, unsigned argc, jsval *vp)
# define FMT_STR(str)
# define PARAM_ADDR(w)
#endif
char *sz = JS_smprintf("[object %s" FMT_ADDR FMT_STR(" (native") FMT_ADDR FMT_STR(")") "]", si->GetJSClass()->name PARAM_ADDR(obj) PARAM_ADDR(xpc_GetJSPrivate(obj)));
char *sz = JS_smprintf("[object %s" FMT_ADDR FMT_STR(" (native") FMT_ADDR FMT_STR(")") "]", si->GetJSClass()->name PARAM_ADDR(obj.get()) PARAM_ADDR(xpc_GetJSPrivate(obj)));
if (!sz)
return false;
@ -473,7 +473,7 @@ DefinePropertyIfFound(XPCCallContext& ccx,
static JSBool
XPC_WN_OnlyIWrite_AddPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
{
XPCCallContext ccx(JS_CALLER, cx, obj, nullptr, id);
XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id);
XPCWrappedNative* wrapper = ccx.GetWrapper();
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
@ -701,7 +701,7 @@ static JSBool
XPC_WN_NoHelper_Resolve(JSContext *cx, JSHandleObject obj, JSHandleId id)
{
MORPH_SLIM_WRAPPER(cx, obj);
XPCCallContext ccx(JS_CALLER, cx, obj, nullptr, id);
XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id);
XPCWrappedNative* wrapper = ccx.GetWrapper();
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
@ -962,7 +962,7 @@ XPC_WN_Helper_Call(JSContext *cx, unsigned argc, jsval *vp)
// N.B. we want obj to be the callee, not JS_THIS(cx, vp)
RootedObject obj(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
XPCCallContext ccx(JS_CALLER, cx, obj, nullptr, JSID_VOID,
XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), JSID_VOIDHANDLE,
argc, JS_ARGV(cx, vp), vp);
if (!ccx.IsValid())
return false;
@ -982,7 +982,7 @@ XPC_WN_Helper_Construct(JSContext *cx, unsigned argc, jsval *vp)
if (!obj)
return false;
XPCCallContext ccx(JS_CALLER, cx, obj, nullptr, JSID_VOID,
XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), JSID_VOIDHANDLE,
argc, JS_ARGV(cx, vp), vp);
if (!ccx.IsValid())
return false;
@ -1472,7 +1472,8 @@ XPC_WN_CallMethod(JSContext *cx, unsigned argc, jsval *vp)
return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
obj = FixUpThisIfBroken(obj, funobj);
XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOID, argc, JS_ARGV(cx, vp), vp);
XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, argc,
JS_ARGV(cx, vp), vp);
XPCWrappedNative* wrapper = ccx.GetWrapper();
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
@ -1511,7 +1512,8 @@ XPC_WN_GetterSetter(JSContext *cx, unsigned argc, jsval *vp)
obj = FixUpThisIfBroken(obj, funobj);
XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOID, argc, JS_ARGV(cx, vp), vp);
XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, argc,
JS_ARGV(cx, vp), vp);
XPCWrappedNative* wrapper = ccx.GetWrapper();
THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);

View File

@ -2421,13 +2421,13 @@ const uint8_t HAS_ORIGIN_PRINCIPALS_FLAG = 2;
static nsresult
WriteScriptOrFunction(nsIObjectOutputStream *stream, JSContext *cx,
JSScript *script, HandleObject functionObj)
JSScript *scriptArg, HandleObject functionObj)
{
// Exactly one of script or functionObj must be given
MOZ_ASSERT(!script != !functionObj);
MOZ_ASSERT(!scriptArg != !functionObj);
if (!script)
script = JS_GetFunctionScript(cx, JS_GetObjectFunction(functionObj));
RootedScript script(cx, scriptArg ? scriptArg :
JS_GetFunctionScript(cx, JS_GetObjectFunction(functionObj)));
nsIPrincipal *principal =
nsJSPrincipals::get(JS_GetScriptPrincipals(script));

View File

@ -1139,14 +1139,16 @@ public:
enum {NO_ARGS = (unsigned) -1};
static JSContext* GetDefaultJSContext();
XPCCallContext(XPCContext::LangType callerLanguage,
JSContext* cx = nullptr,
JSObject* obj = nullptr,
JSObject* funobj = nullptr,
jsid id = JSID_VOID,
unsigned argc = NO_ARGS,
jsval *argv = nullptr,
jsval *rval = nullptr);
JSContext* cx = GetDefaultJSContext(),
JS::HandleObject obj = JS::NullPtr(),
JS::HandleObject funobj = JS::NullPtr(),
JS::HandleId id = JS::JSID_VOIDHANDLE,
unsigned argc = NO_ARGS,
jsval *argv = nullptr,
jsval *rval = nullptr);
virtual ~XPCCallContext();
@ -1200,7 +1202,7 @@ public:
inline void SetDestroyJSContextInDestructor(JSBool b);
inline jsid GetResolveName() const;
inline jsid SetResolveName(jsid name);
inline jsid SetResolveName(JS::HandleId name);
inline XPCWrappedNative* GetResolvingWrapper() const;
inline XPCWrappedNative* SetResolvingWrapper(XPCWrappedNative* w);
@ -1228,8 +1230,8 @@ private:
XPCCallContext(XPCContext::LangType callerLanguage,
JSContext* cx,
JSBool callBeginRequest,
JSObject* obj,
JSObject* flattenedJSObject,
JS::HandleObject obj,
JS::HandleObject flattenedJSObject,
XPCWrappedNative* wn,
XPCWrappedNativeTearOff* tearoff);
@ -1240,15 +1242,15 @@ private:
void Init(XPCContext::LangType callerLanguage,
JSBool callBeginRequest,
JSObject* obj,
JSObject* funobj,
JS::HandleObject obj,
JS::HandleObject funobj,
WrapperInitOptions wrapperInitOptions,
jsid name,
JS::HandleId name,
unsigned argc,
jsval *argv,
jsval *rval);
XPCWrappedNative* UnwrapThisIfAllowed(JSObject *obj, JSObject *fun,
XPCWrappedNative* UnwrapThisIfAllowed(JS::HandleObject obj, JS::HandleObject fun,
unsigned argc);
private:
@ -1399,12 +1401,14 @@ public:
{
if (!mCcx) {
XPCCallContext *data = mData.addr();
xpc_UnmarkGrayObject(mObj);
xpc_UnmarkGrayObject(mFlattenedJSObject);
mCcxToDestroy = mCcx =
new (data) XPCCallContext(mCallerLanguage, mCx,
mCallBeginRequest == CALL_BEGINREQUEST,
xpc_UnmarkGrayObject(mObj),
xpc_UnmarkGrayObject(mFlattenedJSObject),
mWrapper,
mObj,
mFlattenedJSObject,
mWrapper,
mTearOff);
if (!mCcx->IsValid()) {
NS_ERROR("This is not supposed to fail!");
@ -2516,7 +2520,7 @@ class xpcObjectHelper;
extern JSBool ConstructSlimWrapper(XPCCallContext &ccx,
xpcObjectHelper &aHelper,
XPCWrappedNativeScope* xpcScope,
jsval *rval);
JS::MutableHandleValue rval);
extern JSBool MorphSlimWrapper(JSContext *cx, JS::HandleObject obj);
/***********************************************/
@ -3301,7 +3305,7 @@ public:
const void* s, const nsXPTType& type,
const nsID* iid, nsresult* pErr);
static JSBool JSData2Native(JSContext* cx, void* d, jsval s,
static JSBool JSData2Native(JSContext* cx, void* d, JS::HandleValue s,
const nsXPTType& type,
JSBool useAllocator, const nsID* iid,
nsresult* pErr);
@ -3349,7 +3353,7 @@ public:
const nsID* iid,
nsresult* pErr);
static JSBool JSObject2NativeInterface(JSContext* cx,
void** dest, JSObject* src,
void** dest, JS::HandleObject src,
const nsID* iid,
nsISupports* aOuter,
nsresult* pErr);
@ -3832,7 +3836,7 @@ private:
class MOZ_STACK_CLASS AutoResolveName
{
public:
AutoResolveName(XPCCallContext& ccx, jsid name
AutoResolveName(XPCCallContext& ccx, JS::HandleId name
MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
mOld(ccx, XPCJSRuntime::Get()->SetResolveName(name))
#ifdef DEBUG

View File

@ -166,8 +166,11 @@ IsPermitted(const char *name, JSFlatString *prop, bool set)
#undef W
static bool
IsFrameId(JSContext *cx, JSObject *obj, jsid id)
IsFrameId(JSContext *cx, JSObject *objArg, jsid idArg)
{
RootedObject obj(cx, objArg);
RootedId id(cx, idArg);
obj = JS_ObjectToInnerObject(cx, obj);
MOZ_ASSERT(!js::IsWrapper(obj));
XPCWrappedNative *wn = IS_WN_WRAPPER(obj) ? XPCWrappedNative::Get(obj)
@ -279,14 +282,16 @@ EnterAndThrow(JSContext *cx, JSObject *wrapper, const char *msg)
}
bool
ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act)
ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapperArg, jsid idArg, Wrapper::Action act)
{
JSObject *wrappedObject = Wrapper::wrappedObject(wrapper);
RootedObject wrapper(cx, wrapperArg);
RootedId id(cx, idArg);
RootedObject wrappedObject(cx, Wrapper::wrappedObject(wrapper));
if (act == Wrapper::CALL)
return true;
jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS);
RootedId exposedPropsId(cx, GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS));
// We need to enter the wrappee's compartment to look at __exposedProps__,
// but we want to be in the wrapper's compartment if we call Deny().
@ -314,8 +319,8 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
if (id == JSID_VOID)
return true;
JS::Value exposedProps;
if (!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, &exposedProps))
RootedValue exposedProps(cx);
if (!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, exposedProps.address()))
return false;
if (exposedProps.isNullOrUndefined())
@ -398,8 +403,10 @@ ExposedPropertiesOnly::allowNativeCall(JSContext *cx, JS::IsAcceptableThis test,
}
bool
ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act)
ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapperArg, jsid idArg, Wrapper::Action act)
{
RootedObject wrapper(cx, wrapperArg);
RootedId id(cx, idArg);
JSAutoCompartment ac(cx, wrapper);
if (JSID_IS_STRING(id) && act == Wrapper::GET) {

View File

@ -1,5 +1,7 @@
#include "ChromeObjectWrapper.h"
using namespace JS;
namespace xpc {
// When creating wrappers for chrome objects in content, we detect if the
@ -17,7 +19,7 @@ ChromeObjectWrapper ChromeObjectWrapper::singleton;
using js::assertEnteredPolicy;
static bool
AllowedByBase(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
AllowedByBase(JSContext *cx, HandleObject wrapper, HandleId id,
js::Wrapper::Action act)
{
MOZ_ASSERT(js::Wrapper::wrapperHandler(wrapper) ==
@ -31,7 +33,7 @@ static bool
PropIsFromStandardPrototype(JSContext *cx, JSPropertyDescriptor *desc)
{
MOZ_ASSERT(desc->obj);
JSObject *unwrapped = js::UncheckedUnwrap(desc->obj);
RootedObject unwrapped(cx, js::UncheckedUnwrap(desc->obj));
JSAutoCompartment ac(cx, unwrapped);
return JS_IdentifyClassPrototype(cx, unwrapped) != JSProto_Null;
}
@ -41,26 +43,26 @@ PropIsFromStandardPrototype(JSContext *cx, JSPropertyDescriptor *desc)
// This lets us determine whether the property we would have found (given a
// transparent wrapper) would have come off a standard prototype.
static bool
PropIsFromStandardPrototype(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id)
PropIsFromStandardPrototype(JSContext *cx, HandleObject wrapper,
HandleId id)
{
MOZ_ASSERT(js::Wrapper::wrapperHandler(wrapper) ==
&ChromeObjectWrapper::singleton);
JSPropertyDescriptor desc;
Rooted<JSPropertyDescriptor> desc(cx);
ChromeObjectWrapper *handler = &ChromeObjectWrapper::singleton;
if (!handler->ChromeObjectWrapperBase::getPropertyDescriptor(cx, wrapper, id,
&desc, 0) ||
!desc.obj)
desc.address(), 0) ||
!desc.object())
{
return false;
}
return PropIsFromStandardPrototype(cx, &desc);
return PropIsFromStandardPrototype(cx, desc.address());
}
bool
ChromeObjectWrapper::getPropertyDescriptor(JSContext *cx,
JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id,
HandleObject wrapper,
HandleId id,
js::PropertyDescriptor *desc,
unsigned flags)
{
@ -80,8 +82,8 @@ ChromeObjectWrapper::getPropertyDescriptor(JSContext *cx,
desc->obj = NULL;
// If we found something or have no proto, we're done.
JSObject *wrapperProto;
if (!JS_GetPrototype(cx, wrapper, &wrapperProto))
RootedObject wrapperProto(cx);
if (!JS_GetPrototype(cx, wrapper, wrapperProto.address()))
return false;
if (desc->obj || !wrapperProto)
return true;
@ -92,8 +94,8 @@ ChromeObjectWrapper::getPropertyDescriptor(JSContext *cx,
}
bool
ChromeObjectWrapper::has(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id, bool *bp)
ChromeObjectWrapper::has(JSContext *cx, HandleObject wrapper,
HandleId id, bool *bp)
{
assertEnteredPolicy(cx, wrapper, id);
// Try the lookup on the base wrapper if permitted.
@ -104,25 +106,25 @@ ChromeObjectWrapper::has(JSContext *cx, JS::Handle<JSObject*> wrapper,
}
// If we found something or have no prototype, we're done.
JSObject *wrapperProto;
if (!JS_GetPrototype(cx, wrapper, &wrapperProto))
RootedObject wrapperProto(cx);
if (!JS_GetPrototype(cx, wrapper, wrapperProto.address()))
return false;
if (*bp || !wrapperProto)
return true;
// Try the prototype if that failed.
MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
JSPropertyDescriptor desc;
if (!JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, &desc))
Rooted<JSPropertyDescriptor> desc(cx);
if (!JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, desc.address()))
return false;
*bp = !!desc.obj;
*bp = !!desc.object();
return true;
}
bool
ChromeObjectWrapper::get(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> receiver, JS::Handle<jsid> id,
JS::MutableHandle<JS::Value> vp)
ChromeObjectWrapper::get(JSContext *cx, HandleObject wrapper,
HandleObject receiver, HandleId id,
MutableHandleValue vp)
{
assertEnteredPolicy(cx, wrapper, id);
vp.setUndefined();
@ -142,8 +144,8 @@ ChromeObjectWrapper::get(JSContext *cx, JS::Handle<JSObject*> wrapper,
}
// If we have no proto, we're done.
JSObject *wrapperProto;
if (!JS_GetPrototype(cx, wrapper, &wrapperProto))
RootedObject wrapperProto(cx);
if (!JS_GetPrototype(cx, wrapper, wrapperProto.address()))
return false;
if (!wrapperProto)
return true;
@ -157,7 +159,7 @@ ChromeObjectWrapper::get(JSContext *cx, JS::Handle<JSObject*> wrapper,
// contacts API depends on Array.isArray returning true for COW-implemented
// contacts. This isn't really ideal, but make it work for now.
bool
ChromeObjectWrapper::objectClassIs(JS::Handle<JSObject*> obj, js::ESClassValue classValue,
ChromeObjectWrapper::objectClassIs(HandleObject obj, js::ESClassValue classValue,
JSContext *cx)
{
return CrossCompartmentWrapper::objectClassIs(obj, classValue, cx);
@ -168,8 +170,8 @@ ChromeObjectWrapper::objectClassIs(JS::Handle<JSObject*> obj, js::ESClassValue c
// enforcement or COWs isn't cheap. But it results in the cleanest code, and this
// whole proto remapping thing for COWs is going to be phased out anyway.
bool
ChromeObjectWrapper::enter(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id, js::Wrapper::Action act, bool *bp)
ChromeObjectWrapper::enter(JSContext *cx, HandleObject wrapper,
HandleId id, js::Wrapper::Action act, bool *bp)
{
if (AllowedByBase(cx, wrapper, id, act))
return true;
@ -181,9 +183,7 @@ ChromeObjectWrapper::enter(JSContext *cx, JS::Handle<JSObject*> wrapper,
// Note that PropIsFromStandardPrototype needs to invoke getPropertyDescriptor
// before we've fully entered the policy. Waive our policy.
JS::RootedObject rootedWrapper(cx, wrapper);
JS::RootedId rootedId(cx, id);
js::AutoWaivePolicy policy(cx, rootedWrapper, rootedId);
js::AutoWaivePolicy policy(cx, wrapper, id);
return PropIsFromStandardPrototype(cx, wrapper, id);
}

View File

@ -38,11 +38,12 @@ FilteringWrapper<Base, Policy>::isSafeToUnwrap()
template <typename Policy>
static bool
Filter(JSContext *cx, JS::Handle<JSObject*> wrapper, AutoIdVector &props)
Filter(JSContext *cx, HandleObject wrapper, AutoIdVector &props)
{
size_t w = 0;
RootedId id(cx);
for (size_t n = 0; n < props.length(); ++n) {
jsid id = props[n];
id = props[n];
if (Policy::check(cx, wrapper, id, Wrapper::GET))
props[w++] = id;
else if (JS_IsExceptionPending(cx))
@ -67,8 +68,8 @@ FilterSetter(JSContext *cx, JSObject *wrapper, jsid id, js::PropertyDescriptor *
template <typename Base, typename Policy>
bool
FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id,
FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, HandleObject wrapper,
HandleId id,
js::PropertyDescriptor *desc, unsigned flags)
{
assertEnteredPolicy(cx, wrapper, id);
@ -79,8 +80,8 @@ FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, JS::Handle<
template <typename Base, typename Policy>
bool
FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id,
FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper,
HandleId id,
js::PropertyDescriptor *desc,
unsigned flags)
{
@ -92,7 +93,7 @@ FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(JSContext *cx, JS::Hand
template <typename Base, typename Policy>
bool
FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, JS::Handle<JSObject*> wrapper,
FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
@ -102,7 +103,7 @@ FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, JS::Handle<JS
template <typename Base, typename Policy>
bool
FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper,
FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, HandleObject wrapper,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
@ -112,7 +113,7 @@ FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, JS::Handle<JSObject*> w
template <typename Base, typename Policy>
bool
FilteringWrapper<Base, Policy>::keys(JSContext *cx, JS::Handle<JSObject*> wrapper,
FilteringWrapper<Base, Policy>::keys(JSContext *cx, HandleObject wrapper,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
@ -122,8 +123,8 @@ FilteringWrapper<Base, Policy>::keys(JSContext *cx, JS::Handle<JSObject*> wrappe
template <typename Base, typename Policy>
bool
FilteringWrapper<Base, Policy>::iterate(JSContext *cx, JS::Handle<JSObject*> wrapper,
unsigned flags, JS::MutableHandle<JS::Value> vp)
FilteringWrapper<Base, Policy>::iterate(JSContext *cx, HandleObject wrapper,
unsigned flags, MutableHandleValue vp)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
// We refuse to trigger the iterator hook across chrome wrappers because
@ -145,7 +146,7 @@ FilteringWrapper<Base, Policy>::nativeCall(JSContext *cx, JS::IsAcceptableThis t
template <typename Base, typename Policy>
bool
FilteringWrapper<Base, Policy>::defaultValue(JSContext *cx, JS::Handle<JSObject*> obj,
FilteringWrapper<Base, Policy>::defaultValue(JSContext *cx, HandleObject obj,
JSType hint, MutableHandleValue vp)
{
return Base::defaultValue(cx, obj, hint, vp);
@ -156,7 +157,7 @@ FilteringWrapper<Base, Policy>::defaultValue(JSContext *cx, JS::Handle<JSObject*
template<>
bool
FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
::defaultValue(JSContext *cx, JS::Handle<JSObject*> obj,
::defaultValue(JSContext *cx, HandleObject obj,
JSType hint, MutableHandleValue vp)
{
JSString *str = JS_NewStringCopyZ(cx, "[Opaque]");
@ -169,8 +170,8 @@ FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>
template <typename Base, typename Policy>
bool
FilteringWrapper<Base, Policy>::enter(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id, Wrapper::Action act, bool *bp)
FilteringWrapper<Base, Policy>::enter(JSContext *cx, HandleObject wrapper,
HandleId id, Wrapper::Action act, bool *bp)
{
// This is a super ugly hacky to get around Xray Resolve wonkiness.
//

View File

@ -13,21 +13,23 @@
#include "AccessCheck.h"
#include "WrapperFactory.h"
using namespace JS;
namespace xpc {
static bool
WaiveAccessors(JSContext *cx, js::PropertyDescriptor *desc)
{
if ((desc->attrs & JSPROP_GETTER) && desc->getter) {
JS::Value v = JS::ObjectValue(*JS_FUNC_TO_DATA_PTR(JSObject *, desc->getter));
if (!WrapperFactory::WaiveXrayAndWrap(cx, &v))
RootedValue v(cx, JS::ObjectValue(*JS_FUNC_TO_DATA_PTR(JSObject *, desc->getter)));
if (!WrapperFactory::WaiveXrayAndWrap(cx, v.address()))
return false;
desc->getter = js::CastAsJSPropertyOp(&v.toObject());
}
if ((desc->attrs & JSPROP_SETTER) && desc->setter) {
JS::Value v = JS::ObjectValue(*JS_FUNC_TO_DATA_PTR(JSObject *, desc->setter));
if (!WrapperFactory::WaiveXrayAndWrap(cx, &v))
RootedValue v(cx, JS::ObjectValue(*JS_FUNC_TO_DATA_PTR(JSObject *, desc->setter)));
if (!WrapperFactory::WaiveXrayAndWrap(cx, v.address()))
return false;
desc->setter = js::CastAsJSStrictPropertyOp(&v.toObject());
}
@ -43,8 +45,8 @@ WaiveXrayWrapper::~WaiveXrayWrapper()
}
bool
WaiveXrayWrapper::getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*>wrapper,
JS::Handle<jsid> id, js::PropertyDescriptor *desc,
WaiveXrayWrapper::getPropertyDescriptor(JSContext *cx, HandleObject wrapper,
HandleId id, js::PropertyDescriptor *desc,
unsigned flags)
{
return CrossCompartmentWrapper::getPropertyDescriptor(cx, wrapper, id, desc, flags) &&
@ -52,8 +54,8 @@ WaiveXrayWrapper::getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*>wrap
}
bool
WaiveXrayWrapper::getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<jsid> id, js::PropertyDescriptor *desc,
WaiveXrayWrapper::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper,
HandleId id, js::PropertyDescriptor *desc,
unsigned flags)
{
return CrossCompartmentWrapper::getOwnPropertyDescriptor(cx, wrapper, id, desc, flags) &&
@ -61,23 +63,23 @@ WaiveXrayWrapper::getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*>
}
bool
WaiveXrayWrapper::get(JSContext *cx, JS::Handle<JSObject*> wrapper,
JS::Handle<JSObject*> receiver, JS::Handle<jsid> id,
JS::MutableHandle<JS::Value> vp)
WaiveXrayWrapper::get(JSContext *cx, HandleObject wrapper,
HandleObject receiver, HandleId id,
MutableHandleValue vp)
{
return CrossCompartmentWrapper::get(cx, wrapper, receiver, id, vp) &&
WrapperFactory::WaiveXrayAndWrap(cx, vp.address());
}
bool
WaiveXrayWrapper::call(JSContext *cx, JS::Handle<JSObject*> wrapper, const JS::CallArgs &args)
WaiveXrayWrapper::call(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args)
{
return CrossCompartmentWrapper::call(cx, wrapper, args) &&
WrapperFactory::WaiveXrayAndWrap(cx, args.rval().address());
}
bool
WaiveXrayWrapper::construct(JSContext *cx, JS::Handle<JSObject*> wrapper, const JS::CallArgs &args)
WaiveXrayWrapper::construct(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args)
{
return CrossCompartmentWrapper::construct(cx, wrapper, args) &&
WrapperFactory::WaiveXrayAndWrap(cx, args.rval().address());

View File

@ -69,15 +69,15 @@ WrapperFactory::CreateXrayWaiver(JSContext *cx, HandleObject obj)
XPCWrappedNativeScope *scope = GetObjectScope(obj);
// Get a waiver for the proto.
JSObject *proto;
if (!js::GetObjectProto(cx, obj, &proto))
RootedObject proto(cx);
if (!js::GetObjectProto(cx, obj, proto.address()))
return nullptr;
if (proto && !(proto = WaiveXray(cx, proto)))
return nullptr;
// Create the waiver.
JSAutoCompartment ac(cx, obj);
if (!JS_WrapObject(cx, &proto))
if (!JS_WrapObject(cx, proto.address()))
return nullptr;
JSObject *waiver = Wrapper::New(cx, obj, proto,
JS_GetGlobalForObject(cx, obj),

View File

@ -756,7 +756,8 @@ XPCWrappedNativeXrayTraits::resolveNativeProperty(JSContext *cx, HandleObject wr
desc->obj = NULL;
// This will do verification and the method lookup for us.
XPCCallContext ccx(JS_CALLER, cx, getTargetObject(wrapper), nullptr, id);
RootedObject target(cx, getTargetObject(wrapper));
XPCCallContext ccx(JS_CALLER, cx, target, NullPtr(), id);
// There are no native numeric properties, so we can shortcut here. We will
// not find the property. However we want to support non shadowing dom
@ -1115,8 +1116,8 @@ XPCWrappedNativeXrayTraits::call(JSContext *cx, HandleObject wrapper,
// Run the resolve hook of the wrapped native.
XPCWrappedNative *wn = getWN(wrapper);
if (NATIVE_HAS_FLAG(wn, WantCall)) {
XPCCallContext ccx(JS_CALLER, cx, wrapper, nullptr, JSID_VOID, args.length(), args.array(),
args.rval().address());
XPCCallContext ccx(JS_CALLER, cx, wrapper, NullPtr(), JSID_VOIDHANDLE, args.length(),
args.array(), args.rval().address());
if (!ccx.IsValid())
return false;
bool ok = true;
@ -1140,8 +1141,8 @@ XPCWrappedNativeXrayTraits::construct(JSContext *cx, HandleObject wrapper,
// Run the resolve hook of the wrapped native.
XPCWrappedNative *wn = getWN(wrapper);
if (NATIVE_HAS_FLAG(wn, WantConstruct)) {
XPCCallContext ccx(JS_CALLER, cx, wrapper, nullptr, JSID_VOID, args.length(), args.array(),
args.rval().address());
XPCCallContext ccx(JS_CALLER, cx, wrapper, NullPtr(), JSID_VOIDHANDLE, args.length(),
args.array(), args.rval().address());
if (!ccx.IsValid())
return false;
bool ok = true;

View File

@ -11,11 +11,11 @@
#include "nsCSSFrameConstructor.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/HTMLSelectElement.h"
#include "mozilla/Likely.h"
#include "mozilla/LinkedList.h"
#include "nsAbsoluteContainingBlock.h"
#include "nsCRT.h"
#include "nsIAtom.h"
@ -1415,6 +1415,7 @@ nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument,
, mDocElementContainingBlock(nullptr)
, mGfxScrollFrame(nullptr)
, mPageSequenceFrame(nullptr)
, mCurrentDepth(0)
, mUpdateCount(0)
, mQuotesDirty(false)
, mCountersDirty(false)
@ -9841,6 +9842,12 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
NS_PRECONDITION(aFrame->GetContentInsertionFrame() == aFrame,
"Parent frame in ProcessChildren should be its own "
"content insertion frame");
const uint32_t kMaxDepth = 2 * MAX_REFLOW_DEPTH;
MOZ_STATIC_ASSERT(kMaxDepth <= UINT16_MAX, "mCurrentDepth type is too narrow");
AutoRestore<uint16_t> savedDepth(mCurrentDepth);
if (mCurrentDepth != UINT16_MAX) {
++mCurrentDepth;
}
if (!aPossiblyLeafFrame) {
aPossiblyLeafFrame = aFrame;
@ -9938,6 +9945,11 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
itemsToConstruct);
}
const bool addChildItems = MOZ_LIKELY(mCurrentDepth < kMaxDepth);
if (!addChildItems) {
NS_WARNING("ProcessChildren max depth exceeded");
}
ChildIterator iter, last;
for (ChildIterator::Init(aContent, &iter, &last);
iter != last;
@ -9948,8 +9960,12 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
if (child->IsElement()) {
child->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
}
AddFrameConstructionItems(aState, child, iter.XBLInvolved(), aFrame,
itemsToConstruct);
if (addChildItems) {
AddFrameConstructionItems(aState, child, iter.XBLInvolved(), aFrame,
itemsToConstruct);
} else {
ClearLazyBits(child, child->GetNextSibling());
}
}
itemsToConstruct.SetParentHasNoXBLChildren(!iter.XBLInvolved());

View File

@ -1878,6 +1878,8 @@ private:
nsIFrame* mPageSequenceFrame;
nsQuoteList mQuoteList;
nsCounterManager mCounterManager;
// Current ProcessChildren depth.
uint16_t mCurrentDepth;
uint16_t mUpdateCount;
bool mQuotesDirty : 1;
bool mCountersDirty : 1;

View File

@ -151,6 +151,14 @@ MOCHITEST_FILES = \
bug851445_helper.html \
$(NULL)
ifeq (,$(filter gonk,$(MOZ_WIDGET_TOOLKIT)))
# THESE TESTS (BELOW) DO NOT RUN ON B2G
MOCHITEST_FILES += \
test_bug858459.html \
$(NULL)
# THESE TESTS (ABOVE) DO NOT RUN ON B2G
endif
# Tests for bugs 441782, 467672 and 570378 don't pass reliably on Windows, because of bug 469208
ifeq (,$(filter windows,$(MOZ_WIDGET_TOOLKIT)))
# THESE TESTS (BELOW) DO NOT RUN ON WINDOWS

View File

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=858459
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 858459</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 858459 **/
var result = "";
var timeout = null;
var clicks = 0;
const EXPECTED_RESULT = "change select";
function logEvent(ev,msg) {
result += ev.type + ' ' + msg;
++clicks;
if (result.length > EXPECTED_RESULT.length)
finishTest();
}
document.onclick = function(event) { logEvent(event,"document"); }
SimpleTest.waitForExplicitFinish();
function finishTest() {
if (!timeout) return;
clearTimeout(timeout);
timeout = null;
is(result,EXPECTED_RESULT,"");
SimpleTest.finish();
}
function runTest() {
// Need a timeout to check that an event has _not_ occurred.
timeout = setTimeout(finishTest, 5000);
synthesizeMouseAtCenter(document.getElementById('test858459'), { });
}
</script>
</head>
<body onload="SimpleTest.waitForFocus(runTest)">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=858459">Mozilla Bug 858459</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test"><div><select id="test858459" size=4 onclick="logEvent(event,'select');" onchange="logEvent(event,'select');var div = document.querySelector('#test div'); div.innerHTML='<p>'+div.innerHTML; document.body.offsetHeight;"><option>1111111111111111<option>2<option>3</select></div>
</pre>
</body>
</html>

View File

@ -0,0 +1,32 @@
/* -*- Mode: C++; 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/. */
/*
* This CSS stylesheet defines the rules to be applied to any ImageDocuments,
* including those in frames.
*/
@media not print {
.overflowing {
cursor: -moz-zoom-out;
}
.shrinkToFit,
.scaleToDevicePixels {
cursor: -moz-zoom-in;
}
}
@media print {
/* We must declare the image as a block element. If we stay as
an inline element, our parent LineBox will be inline too and
ignore the available height during reflow.
This is bad during printing, it means tall image frames won't know
the size of the paper and cannot break into continuations along
multiple pages. */
img {
display: block;
}
}

View File

@ -87,6 +87,7 @@ LOCAL_INCLUDES += \
_FILES = \
contenteditable.css \
designmode.css \
ImageDocument.css \
TopLevelImageDocument.css \
TopLevelVideoDocument.css \
$(NULL)

View File

@ -22,16 +22,8 @@
bottom: 0;
left: 0;
}
}
@media print {
/* We must declare the image as a block element. If we stay as
an inline element, our parent LineBox will be inline too and
ignore the available height during reflow.
This is bad during printing, it means tall image frames won't know
the size of the paper and cannot break into continuations along
multiple pages. */
img {
display: block;
.completeRotation {
transition: transform 0.3s ease 0s;
}
}

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