This commit is contained in:
Wes Kocher 2013-12-16 21:35:20 -08:00
Родитель 9a51f719e2 56c7fcbb4e
Коммит a48372de5d
117 изменённых файлов: 5911 добавлений и 3089 удалений

Просмотреть файл

@ -15,7 +15,7 @@ EXPORTS += [
'ia2AccessibleValue.h',
]
SOURCES += [
UNIFIED_SOURCES += [
'ia2Accessible.cpp',
'ia2AccessibleAction.cpp',
'ia2AccessibleComponent.cpp',
@ -24,12 +24,17 @@ SOURCES += [
'ia2AccessibleHypertext.cpp',
'ia2AccessibleImage.cpp',
'ia2AccessibleRelation.cpp',
'ia2AccessibleTable.cpp',
'ia2AccessibleTableCell.cpp',
'ia2AccessibleText.cpp',
'ia2AccessibleValue.cpp',
]
# These files cannot be built in unified mode because they both include
# AccessibleTable2_i.c.
SOURCES += [
'ia2AccessibleTable.cpp',
'ia2AccessibleTableCell.cpp',
]
LOCAL_INCLUDES += [
'../../base',
'../../generic',

Просмотреть файл

@ -14,7 +14,7 @@ EXPORTS.mozilla.a11y += [
'HyperTextAccessibleWrap.h',
]
SOURCES += [
UNIFIED_SOURCES += [
'AccessibleWrap.cpp',
'ApplicationAccessibleWrap.cpp',
'ARIAGridAccessibleWrap.cpp',
@ -29,12 +29,16 @@ SOURCES += [
'nsWinUtils.cpp',
'Platform.cpp',
'RootAccessibleWrap.cpp',
'ServiceProvider.cpp',
'TextLeafAccessibleWrap.cpp',
]
# This file cannot be built in unified mode because it includes ISimpleDOMNode_i.c.
SOURCES += [
'ServiceProvider.cpp',
]
if CONFIG['MOZ_XUL']:
SOURCES += [
UNIFIED_SOURCES += [
'XULListboxAccessibleWrap.cpp',
'XULMenuAccessibleWrap.cpp',
'XULTreeGridAccessibleWrap.cpp',

Просмотреть файл

@ -4,7 +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/.
SOURCES += [
UNIFIED_SOURCES += [
'sdnAccessible.cpp',
'sdnDocAccessible.cpp',
'sdnTextAccessible.cpp',

Просмотреть файл

@ -29,7 +29,7 @@ endif
endif # WINNT
ifdef .PYMAKE
include_deps = $(eval -includedeps $(1))
include_deps = $(eval $(if $(2),,-)includedeps $(1))
else
include_deps = $(eval -include $(1))
include_deps = $(eval $(if $(2),,-)include $(1))
endif

Просмотреть файл

@ -116,11 +116,19 @@ void main(void) {
checkGLError(ok, info);
var elemTestFunc = todo; // We fail on most implementations.
var checkGLTestFunc = todo;
if (DriverInfo.getDriver() == DriverInfo.DRIVER.ANGLE ||
DriverInfo.getOS() == DriverInfo.OS.ANDROID)
{
// ANGLE and Android slaves seem to work fine.
elemTestFunc = ok;
checkGLTestFunc = ok;
}
if (DriverInfo.getDriver() == DriverInfo.DRIVER.ANDROID_X86_EMULATOR)
{
// ...but the Android 4.2 x86 emulator environment is different
elemTestFunc = todo;
checkGLTestFunc = ok;
}
// Now for drawElements:
@ -139,7 +147,7 @@ void main(void) {
gl.drawElements(gl.POINTS, 1, indexType, 2*indexStride);
elemTestFunc(!isScreenBlack(), '[' + info + '] drawElements[huge offset] should color pixels.');
checkGLError(elemTestFunc, info);
checkGLError(checkGLTestFunc, info);
}
// Begin drawing

Просмотреть файл

@ -85,7 +85,11 @@ public:
nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) MOZ_OVERRIDE
{
// XXX: Merge result with audio reader.
return GetVideoReader()->GetBuffered(aBuffered, aStartTime);
MediaDecoderReader* reader = GetVideoReader() ? GetVideoReader() : GetAudioReader();
if (reader) {
return reader->GetBuffered(aBuffered, aStartTime);
}
return NS_OK;
}
MediaQueue<AudioData>& AudioQueue() MOZ_OVERRIDE

Просмотреть файл

@ -11,7 +11,7 @@
namespace MPAPI {
enum ColorFormat {
YCbCr,
I420,
RGB565
};

Просмотреть файл

@ -18,6 +18,7 @@
namespace mozilla {
typedef mozilla::layers::Image Image;
typedef mozilla::layers::PlanarYCbCrImage PlanarYCbCrImage;
MediaPluginReader::MediaPluginReader(AbstractMediaDecoder *aDecoder,
const nsACString& aContentType) :
@ -170,7 +171,7 @@ bool MediaPluginReader::DecodeVideoFrame(bool &aKeyframeSkip,
currentImage = bufferCallback.GetImage();
int64_t pos = mDecoder->GetResource()->Tell();
nsIntRect picture = mPicture;
nsAutoPtr<VideoData> v;
if (currentImage) {
gfx::IntSize frameSize = currentImage->GetSize();
@ -338,33 +339,79 @@ MediaPluginReader::ImageBufferCallback::ImageBufferCallback(mozilla::layers::Ima
void *
MediaPluginReader::ImageBufferCallback::operator()(size_t aWidth, size_t aHeight,
MPAPI::ColorFormat aColorFormat)
MPAPI::ColorFormat aColorFormat)
{
if (!mImageContainer) {
NS_WARNING("No image container to construct an image");
return nullptr;
}
nsRefPtr<Image> rgbImage;
nsRefPtr<Image> image;
switch(aColorFormat) {
case MPAPI::RGB565:
rgbImage = mozilla::layers::CreateSharedRGBImage(mImageContainer,
nsIntSize(aWidth, aHeight),
gfxImageFormatRGB16_565);
if (!rgbImage) {
image = mozilla::layers::CreateSharedRGBImage(mImageContainer,
nsIntSize(aWidth, aHeight),
gfxImageFormatRGB16_565);
if (!image) {
NS_WARNING("Could not create rgb image");
return nullptr;
}
mImage = rgbImage;
return rgbImage->AsSharedImage()->GetBuffer();
case MPAPI::YCbCr:
mImage = image;
return image->AsSharedImage()->GetBuffer();
case MPAPI::I420:
return CreateI420Image(aWidth, aHeight);
default:
NS_NOTREACHED("Color format not supported");
return nullptr;
}
}
uint8_t *
MediaPluginReader::ImageBufferCallback::CreateI420Image(size_t aWidth,
size_t aHeight)
{
ImageFormat format = PLANAR_YCBCR;
mImage = mImageContainer->CreateImage(&format, 1 /* numFormats */);
PlanarYCbCrImage *yuvImage = static_cast<PlanarYCbCrImage *>(mImage.get());
if (!yuvImage) {
NS_WARNING("Could not create I420 image");
return nullptr;
}
size_t frameSize = aWidth * aHeight;
// Allocate enough for one full resolution Y plane
// and two quarter resolution Cb/Cr planes.
uint8_t *buffer = yuvImage->AllocateAndGetNewBuffer(frameSize * 3 / 2);
mozilla::layers::PlanarYCbCrData frameDesc;
frameDesc.mYChannel = buffer;
frameDesc.mCbChannel = buffer + frameSize;
frameDesc.mCrChannel = buffer + frameSize * 5 / 4;
frameDesc.mYSize = gfxIntSize(aWidth, aHeight);
frameDesc.mCbCrSize = gfxIntSize(aWidth / 2, aHeight / 2);
frameDesc.mYStride = aWidth;
frameDesc.mCbCrStride = aWidth / 2;
frameDesc.mYSkip = 0;
frameDesc.mCbSkip = 0;
frameDesc.mCrSkip = 0;
frameDesc.mPicX = 0;
frameDesc.mPicY = 0;
frameDesc.mPicSize = gfxIntSize(aWidth, aHeight);
yuvImage->SetDataNoCopy(frameDesc);
return buffer;
}
already_AddRefed<Image>
MediaPluginReader::ImageBufferCallback::GetImage()
{

Просмотреть файл

@ -65,17 +65,23 @@ public:
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags);
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
class ImageBufferCallback : public MPAPI::BufferCallback {
typedef mozilla::layers::Image Image;
public:
ImageBufferCallback(mozilla::layers::ImageContainer *aImageContainer);
void *operator()(size_t aWidth, size_t aHeight,
MPAPI::ColorFormat aColorFormat) MOZ_OVERRIDE;
already_AddRefed<Image> GetImage();
private:
uint8_t *CreateI420Image(size_t aWidth, size_t aHeight);
mozilla::layers::ImageContainer *mImageContainer;
nsRefPtr<Image> mImage;
};
};
} // namespace mozilla

Просмотреть файл

@ -58,11 +58,10 @@ codegen_dependencies := \
$(GLOBAL_DEPS) \
$(NULL)
$(call include_deps,codegen.pp)
# The 1 is to make codegen.pp not optional.
$(call include_deps,codegen.pp,1)
codegen.pp: codegen.done
codegen.done: $(codegen_dependencies)
codegen.pp: $(codegen_dependencies)
$(call py_action,webidl,$(srcdir))
@$(TOUCH) $@

Просмотреть файл

@ -546,7 +546,7 @@ def create_build_system_manager(topsrcdir, topobjdir, dist_dir):
cache_dir=cache_dir,
# The make rules include a codegen.pp file containing dependencies.
make_deps_path=os.path.join(obj_dir, 'codegen.pp'),
make_deps_target='codegen.done',
make_deps_target='codegen.pp',
)

Просмотреть файл

@ -15,6 +15,7 @@
#include "nsContentUtils.h"
#include "nsPIDOMWindow.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#include "nsJSPrincipals.h"
#include "nsJSUtils.h"
#include "nsPIDOMWindow.h"
@ -60,8 +61,7 @@ class WorkerPromiseTask MOZ_FINAL : public WorkerRunnable
{
public:
WorkerPromiseTask(WorkerPrivate* aWorkerPrivate, Promise* aPromise)
: WorkerRunnable(aWorkerPrivate, WorkerThread,
UnchangedBusyCount, SkipWhenClearing)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
, mPromise(aPromise)
{
MOZ_ASSERT(aPromise);
@ -169,8 +169,7 @@ public:
Promise* aPromise,
JS::Handle<JS::Value> aValue,
Promise::PromiseState aState)
: WorkerRunnable(aWorkerPrivate, WorkerThread,
UnchangedBusyCount, SkipWhenClearing),
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
PromiseResolverMixin(aPromise, aValue, aState)
{}

Просмотреть файл

@ -11,6 +11,7 @@
#include "SharedWorker.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
using mozilla::dom::EventHandlerNonNull;
using mozilla::dom::MessagePortBase;
@ -28,13 +29,10 @@ class DelayedEventRunnable MOZ_FINAL : public WorkerRunnable
public:
DelayedEventRunnable(WorkerPrivate* aWorkerPrivate,
Target aTarget,
TargetAndBusyBehavior aBehavior,
MessagePort* aMessagePort,
nsTArray<nsCOMPtr<nsIDOMEvent>>& aEvents)
: WorkerRunnable(aWorkerPrivate, aTarget,
aTarget == WorkerThread ? ModifyBusyCount : UnchangedBusyCount,
SkipWhenClearing),
mMessagePort(aMessagePort)
: WorkerRunnable(aWorkerPrivate, aBehavior), mMessagePort(aMessagePort)
{
AssertIsOnMainThread();
MOZ_ASSERT(aMessagePort);
@ -109,16 +107,22 @@ MessagePort::Start()
mStarted = true;
if (!mQueuedEvents.IsEmpty()) {
WorkerRunnable::Target target = WorkerRunnable::WorkerThread;
WorkerPrivate* workerPrivate = mWorkerPrivate;
WorkerPrivate* workerPrivate;
WorkerRunnable::TargetAndBusyBehavior behavior;
if (!workerPrivate) {
target = WorkerRunnable::ParentThread;
if (mWorkerPrivate) {
workerPrivate = mWorkerPrivate;
behavior = WorkerRunnable::WorkerThreadModifyBusyCount;
}
else {
workerPrivate = mSharedWorker->GetWorkerPrivate();
MOZ_ASSERT(workerPrivate);
behavior = WorkerRunnable::ParentThreadUnchangedBusyCount;
}
nsRefPtr<DelayedEventRunnable> runnable =
new DelayedEventRunnable(workerPrivate, target, this, mQueuedEvents);
new DelayedEventRunnable(workerPrivate, behavior, this, mQueuedEvents);
runnable->Dispatch(nullptr);
}
}

Просмотреть файл

@ -43,6 +43,7 @@
#include "nsLayoutStatics.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsThread.h"
#include "nsThreadUtils.h"
#include "nsTraceRefcnt.h"
#include "nsXPCOM.h"
@ -50,13 +51,18 @@
#include "OSFileConstants.h"
#include "xpcpublic.h"
#include "SharedWorker.h"
#include "WorkerPrivate.h"
#ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h"
#endif
#ifdef DEBUG
#include "nsThreadManager.h"
#endif
#include "SharedWorker.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -593,6 +599,8 @@ void
ErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aReport)
{
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
MOZ_ASSERT(worker);
return worker->ReportError(aCx, aMessage, aReport);
}
@ -600,6 +608,7 @@ bool
OperationCallback(JSContext* aCx)
{
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
MOZ_ASSERT(worker);
// Now is a good time to turn on profiling if it's pending.
profiler_js_operation_callback();
@ -607,98 +616,42 @@ OperationCallback(JSContext* aCx)
return worker->OperationCallback(aCx);
}
class LogViolationDetailsRunnable : public nsRunnable
class LogViolationDetailsRunnable MOZ_FINAL : public nsRunnable
{
WorkerPrivate* mWorkerPrivate;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
nsString mFileName;
uint32_t mLineNum;
uint32_t mSyncQueueKey;
private:
class LogViolationDetailsResponseRunnable : public WorkerSyncRunnable
{
uint32_t mSyncQueueKey;
public:
LogViolationDetailsResponseRunnable(WorkerPrivate* aWorkerPrivate,
uint32_t aSyncQueueKey)
: WorkerSyncRunnable(aWorkerPrivate, aSyncQueueKey, false),
mSyncQueueKey(aSyncQueueKey)
{
NS_ASSERTION(aWorkerPrivate, "Don't hand me a null WorkerPrivate!");
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
aWorkerPrivate->StopSyncLoop(mSyncQueueKey, true);
return true;
}
bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
AssertIsOnMainThread();
return true;
}
void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{
AssertIsOnMainThread();
}
};
public:
LogViolationDetailsRunnable(WorkerPrivate* aWorker,
const nsString& aFileName,
uint32_t aLineNum)
: mWorkerPrivate(aWorker),
mFileName(aFileName),
mLineNum(aLineNum),
mSyncQueueKey(0)
: mWorkerPrivate(aWorker), mFileName(aFileName), mLineNum(aLineNum)
{
NS_ASSERTION(aWorker, "WorkerPrivate cannot be null");
MOZ_ASSERT(aWorker);
}
NS_DECL_ISUPPORTS_INHERITED
bool
Dispatch(JSContext* aCx)
{
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
mSyncQueueKey = syncLoop.SyncQueueKey();
mSyncLoopTarget = syncLoop.EventTarget();
MOZ_ASSERT(mSyncLoopTarget);
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
JS_ReportError(aCx, "Failed to dispatch to main thread!");
return false;
}
return syncLoop.RunAndForget(aCx);
return syncLoop.Run();
}
NS_IMETHOD
Run()
{
AssertIsOnMainThread();
nsIContentSecurityPolicy* csp = mWorkerPrivate->GetCSP();
if (csp) {
NS_NAMED_LITERAL_STRING(scriptSample,
"Call to eval() or related function blocked by CSP.");
if (mWorkerPrivate->GetReportCSPViolations()) {
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
mFileName, scriptSample, mLineNum, EmptyString());
}
}
nsRefPtr<LogViolationDetailsResponseRunnable> response =
new LogViolationDetailsResponseRunnable(mWorkerPrivate, mSyncQueueKey);
if (!response->Dispatch(nullptr)) {
NS_WARNING("Failed to dispatch response!");
}
return NS_OK;
}
private:
NS_DECL_NSIRUNNABLE
};
bool
@ -715,7 +668,7 @@ ContentSecurityPolicyAllows(JSContext* aCx)
const char* file;
if (JS_DescribeScriptedCaller(aCx, &script, &lineNum) &&
(file = JS_GetScriptFilename(aCx, script))) {
fileName.AssignASCII(file);
fileName = NS_ConvertUTF8toUTF16(file);
} else {
JS_ReportPendingException(aCx);
}
@ -959,81 +912,158 @@ private:
WorkerPrivate* mWorkerPrivate;
};
class WorkerThreadRunnable : public nsRunnable
class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable
{
WorkerPrivate* mWorkerPrivate;
nsRefPtr<RuntimeService::WorkerThread> mThread;
class FinishedRunnable MOZ_FINAL : public nsRunnable
{
nsRefPtr<RuntimeService::WorkerThread> mThread;
public:
FinishedRunnable(already_AddRefed<RuntimeService::WorkerThread> aThread)
: mThread(aThread)
{
MOZ_ASSERT(mThread);
}
NS_DECL_ISUPPORTS_INHERITED
private:
~FinishedRunnable()
{ }
NS_DECL_NSIRUNNABLE
};
public:
WorkerThreadRunnable(WorkerPrivate* aWorkerPrivate)
: mWorkerPrivate(aWorkerPrivate)
WorkerThreadPrimaryRunnable(WorkerPrivate* aWorkerPrivate,
RuntimeService::WorkerThread* aThread)
: mWorkerPrivate(aWorkerPrivate), mThread(aThread)
{
NS_ASSERTION(mWorkerPrivate, "This should never be null!");
MOZ_ASSERT(aWorkerPrivate);
MOZ_ASSERT(aThread);
}
NS_IMETHOD
Run()
NS_DECL_ISUPPORTS_INHERITED
private:
~WorkerThreadPrimaryRunnable()
{ }
NS_DECL_NSIRUNNABLE
};
class WorkerTaskRunnable MOZ_FINAL : public WorkerRunnable
{
nsRefPtr<WorkerTask> mTask;
public:
WorkerTaskRunnable(WorkerPrivate* aWorkerPrivate, WorkerTask* aTask)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mTask(aTask)
{
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
"NuwaMarkCurrentThread is undefined!");
NuwaMarkCurrentThread(nullptr, nullptr);
NuwaFreezeCurrentThread();
}
#endif
WorkerPrivate* workerPrivate = mWorkerPrivate;
mWorkerPrivate = nullptr;
MOZ_ASSERT(aTask);
}
workerPrivate->AssertIsOnWorkerThread();
private:
virtual bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
// May be called on any thread!
return true;
}
{
nsCycleCollector_startup();
virtual void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) MOZ_OVERRIDE
{
// May be called on any thread!
}
WorkerJSRuntime runtime(workerPrivate);
JSRuntime* rt = runtime.Runtime();
JSContext* cx = CreateJSContextForWorker(workerPrivate, rt);
if (!cx) {
// XXX need to fire an error at parent.
NS_ERROR("Failed to create runtime and context!");
return NS_ERROR_FAILURE;
}
char aLocal;
profiler_register_thread("WebWorker", &aLocal);
#ifdef MOZ_ENABLE_PROFILER_SPS
if (PseudoStack* stack = mozilla_get_pseudo_stack())
stack->sampleRuntime(rt);
#endif
{
JSAutoRequest ar(cx);
workerPrivate->DoRunLoop(cx);
}
// Destroy the main context. This will unroot the main worker global and
// GC. This is not the last JSContext (WorkerJSRuntime maintains an
// internal JSContext).
JS_DestroyContext(cx);
// Now WorkerJSRuntime goes out of scope and its destructor will shut
// down the cycle collector and destroy the final JSContext. This
// breaks any remaining cycles and collects the C++ and JS objects
// participating.
}
#ifdef MOZ_ENABLE_PROFILER_SPS
if (PseudoStack* stack = mozilla_get_pseudo_stack())
stack->sampleRuntime(nullptr);
#endif
workerPrivate->ScheduleDeletion(false);
profiler_unregister_thread();
return NS_OK;
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
return mTask->RunTask(aCx);
}
};
} /* anonymous namespace */
class RuntimeService::WorkerThread MOZ_FINAL : public nsThread
{
class Observer MOZ_FINAL : public nsIThreadObserver
{
WorkerPrivate* mWorkerPrivate;
public:
Observer(WorkerPrivate* aWorkerPrivate)
: mWorkerPrivate(aWorkerPrivate)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
}
NS_DECL_THREADSAFE_ISUPPORTS
private:
~Observer()
{
mWorkerPrivate->AssertIsOnWorkerThread();
}
NS_DECL_NSITHREADOBSERVER
};
WorkerPrivate* mWorkerPrivate;
nsRefPtr<Observer> mObserver;
#ifdef DEBUG
// Protected by nsThread::mLock.
bool mAcceptingNonWorkerRunnables;
#endif
public:
static already_AddRefed<WorkerThread>
Create();
void
SetWorker(WorkerPrivate* aWorkerPrivate);
NS_DECL_ISUPPORTS_INHERITED
NS_IMETHOD
Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) MOZ_OVERRIDE;
#ifdef DEBUG
bool
IsAcceptingNonWorkerRunnables()
{
MutexAutoLock lock(mLock);
return mAcceptingNonWorkerRunnables;
}
void
SetAcceptingNonWorkerRunnables(bool aAcceptingNonWorkerRunnables)
{
MutexAutoLock lock(mLock);
mAcceptingNonWorkerRunnables = aAcceptingNonWorkerRunnables;
}
#endif
private:
WorkerThread()
: nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE),
mWorkerPrivate(nullptr)
#ifdef DEBUG
, mAcceptingNonWorkerRunnables(true)
#endif
{ }
~WorkerThread()
{ }
};
BEGIN_WORKERS_NAMESPACE
// Entry point for main thread non-window globals.
@ -1113,71 +1143,64 @@ ResumeWorkersForWindow(nsPIDOMWindow* aWindow)
}
}
namespace {
class WorkerTaskRunnable : public WorkerRunnable
WorkerCrossThreadDispatcher::WorkerCrossThreadDispatcher(
WorkerPrivate* aWorkerPrivate)
: mMutex("WorkerCrossThreadDispatcher::mMutex"),
mWorkerPrivate(aWorkerPrivate)
{
public:
WorkerTaskRunnable(WorkerPrivate* aPrivate, WorkerTask* aTask)
: WorkerRunnable(aPrivate, WorkerThread, UnchangedBusyCount,
SkipWhenClearing),
mTask(aTask)
{ }
virtual bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) {
return true;
}
virtual void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{ }
virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
private:
nsRefPtr<WorkerTask> mTask;
};
bool
WorkerTaskRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
return mTask->RunTask(aCx);
}
MOZ_ASSERT(aWorkerPrivate);
}
bool
WorkerCrossThreadDispatcher::PostTask(WorkerTask* aTask)
{
mozilla::MutexAutoLock lock(mMutex);
if (!mPrivate) {
MOZ_ASSERT(aTask);
MutexAutoLock lock(mMutex);
if (!mWorkerPrivate) {
NS_WARNING("Posted a task to a WorkerCrossThreadDispatcher that is no "
"longer accepting tasks!");
return false;
}
nsRefPtr<WorkerTaskRunnable> runnable = new WorkerTaskRunnable(mPrivate, aTask);
runnable->Dispatch(nullptr);
return true;
nsRefPtr<WorkerTaskRunnable> runnable =
new WorkerTaskRunnable(mWorkerPrivate, aTask);
return runnable->Dispatch(nullptr);
}
WorkerPrivate*
GetWorkerPrivateFromContext(JSContext* aCx)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
return static_cast<WorkerThreadRuntimePrivate*>(JS_GetRuntimePrivate(JS_GetRuntime(aCx)))->mWorkerPrivate;
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aCx);
JSRuntime* rt = JS_GetRuntime(aCx);
MOZ_ASSERT(rt);
void* rtPrivate = JS_GetRuntimePrivate(rt);
MOZ_ASSERT(rtPrivate);
return static_cast<WorkerThreadRuntimePrivate*>(rtPrivate)->mWorkerPrivate;
}
WorkerPrivate*
GetCurrentThreadWorkerPrivate()
{
MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
MOZ_ASSERT(!NS_IsMainThread());
CycleCollectedJSRuntime* ccrt = CycleCollectedJSRuntime::Get();
if (!ccrt) {
return nullptr;
}
JSRuntime* rt = ccrt->Runtime();
return static_cast<WorkerThreadRuntimePrivate*>(JS_GetRuntimePrivate(rt))->
mWorkerPrivate;
MOZ_ASSERT(rt);
void* rtPrivate = JS_GetRuntimePrivate(rt);
MOZ_ASSERT(rtPrivate);
return static_cast<WorkerThreadRuntimePrivate*>(rtPrivate)->mWorkerPrivate;
}
bool
@ -1427,7 +1450,7 @@ RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
}
if (!domainInfo->ActiveWorkerCount()) {
NS_ASSERTION(domainInfo->mQueuedWorkers.IsEmpty(), "Huh?!");
MOZ_ASSERT(domainInfo->mQueuedWorkers.IsEmpty());
mDomainMap.Remove(domain);
}
}
@ -1455,16 +1478,11 @@ RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
nsPIDOMWindow* window = aWorkerPrivate->GetWindow();
nsTArray<WorkerPrivate*>* windowArray;
if (!mWindowMap.Get(window, &windowArray)) {
MOZ_ASSERT(false, "Don't have an entry for this window!");
}
MOZ_ALWAYS_TRUE(mWindowMap.Get(window, &windowArray));
if (!windowArray->RemoveElement(aWorkerPrivate)) {
MOZ_ASSERT(false, "Worker wasn't in the correct window array!");
}
MOZ_ALWAYS_TRUE(windowArray->RemoveElement(aWorkerPrivate));
if (windowArray->IsEmpty()) {
MOZ_ASSERT(!queuedWorker, "queuedWorker should be in this array!");
mWindowMap.Remove(window);
}
}
@ -1482,7 +1500,7 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
return true;
}
nsCOMPtr<nsIThread> thread;
nsRefPtr<WorkerThread> thread;
{
MutexAutoLock lock(mMutex);
if (!mIdleThreadArray.IsEmpty()) {
@ -1493,35 +1511,36 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
}
if (!thread) {
if (NS_FAILED(NS_NewNamedThread("DOM Worker",
getter_AddRefs(thread), nullptr,
WORKER_STACK_SIZE))) {
thread = WorkerThread::Create();
if (!thread) {
UnregisterWorker(aCx, aWorkerPrivate);
JS_ReportError(aCx, "Could not create new thread!");
return false;
}
}
MOZ_ASSERT(thread->IsAcceptingNonWorkerRunnables());
int32_t priority = aWorkerPrivate->IsChromeWorker() ?
nsISupportsPriority::PRIORITY_NORMAL :
nsISupportsPriority::PRIORITY_LOW;
nsCOMPtr<nsISupportsPriority> threadPriority = do_QueryInterface(thread);
if (!threadPriority || NS_FAILED(threadPriority->SetPriority(priority))) {
if (NS_FAILED(thread->SetPriority(priority))) {
NS_WARNING("Could not set the thread's priority!");
}
#ifdef DEBUG
aWorkerPrivate->SetThread(thread);
#endif
nsCOMPtr<nsIRunnable> runnable = new WorkerThreadRunnable(aWorkerPrivate);
nsCOMPtr<nsIRunnable> runnable =
new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread);
if (NS_FAILED(thread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
UnregisterWorker(aCx, aWorkerPrivate);
JS_ReportError(aCx, "Could not dispatch to thread!");
return false;
}
#ifdef DEBUG
thread->SetAcceptingNonWorkerRunnables(false);
#endif
return true;
}
@ -1541,7 +1560,7 @@ RuntimeService::ShutdownIdleThreads(nsITimer* aTimer, void* /* aClosure */)
TimeStamp nextExpiration;
nsAutoTArray<nsCOMPtr<nsIThread>, 20> expiredThreads;
nsAutoTArray<nsRefPtr<WorkerThread>, 20> expiredThreads;
{
MutexAutoLock lock(runtime->mMutex);
@ -1553,7 +1572,7 @@ RuntimeService::ShutdownIdleThreads(nsITimer* aTimer, void* /* aClosure */)
break;
}
nsCOMPtr<nsIThread>* thread = expiredThreads.AppendElement();
nsRefPtr<WorkerThread>* thread = expiredThreads.AppendElement();
thread->swap(info.mThread);
}
@ -1756,7 +1775,6 @@ RuntimeService::Shutdown()
mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers);
if (!workers.IsEmpty()) {
// Cancel all top-level workers.
{
MutexAutoUnlock unlock(mMutex);
@ -1803,7 +1821,7 @@ RuntimeService::Cleanup()
// Shut down any idle threads.
if (!mIdleThreadArray.IsEmpty()) {
nsAutoTArray<nsCOMPtr<nsIThread>, 20> idleThreads;
nsAutoTArray<nsRefPtr<WorkerThread>, 20> idleThreads;
uint32_t idleThreadCount = mIdleThreadArray.Length();
idleThreads.SetLength(idleThreadCount);
@ -2186,10 +2204,14 @@ RuntimeService::ForgetSharedWorker(WorkerPrivate* aWorkerPrivate)
}
void
RuntimeService::NoteIdleThread(nsIThread* aThread)
RuntimeService::NoteIdleThread(WorkerThread* aThread)
{
AssertIsOnMainThread();
NS_ASSERTION(aThread, "Null pointer!");
MOZ_ASSERT(aThread);
#ifdef DEBUG
aThread->SetAcceptingNonWorkerRunnables(true);
#endif
static TimeDuration timeout =
TimeDuration::FromSeconds(IDLE_THREAD_TIMEOUT_SEC);
@ -2216,19 +2238,15 @@ RuntimeService::NoteIdleThread(nsIThread* aThread)
// Too many idle threads, just shut this one down.
if (shutdown) {
if (NS_FAILED(aThread->Shutdown())) {
NS_WARNING("Failed to shutdown thread!");
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aThread->Shutdown()));
return;
}
// Schedule timer.
if (NS_FAILED(mIdleThreadTimer->
InitWithFuncCallback(ShutdownIdleThreads, nullptr,
IDLE_THREAD_TIMEOUT_SEC * 1000,
nsITimer::TYPE_ONE_SHOT))) {
NS_ERROR("Can't schedule timer!");
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mIdleThreadTimer->InitWithFuncCallback(
ShutdownIdleThreads, nullptr,
IDLE_THREAD_TIMEOUT_SEC * 1000,
nsITimer::TYPE_ONE_SHOT)));
}
void
@ -2354,3 +2372,272 @@ RuntimeService::JSVersionChanged(const char* /* aPrefName */, void* /* aClosure
JS::CompartmentOptions& options = sDefaultJSSettings.content.compartmentOptions;
options.setVersion(useLatest ? JSVERSION_LATEST : JSVERSION_DEFAULT);
}
// static
already_AddRefed<RuntimeService::WorkerThread>
RuntimeService::WorkerThread::Create()
{
MOZ_ASSERT(nsThreadManager::get());
nsRefPtr<WorkerThread> thread = new WorkerThread();
if (NS_FAILED(thread->Init())) {
NS_WARNING("Failed to create new thread!");
return nullptr;
}
NS_SetThreadName(thread, "DOM Worker");
return thread.forget();
}
void
RuntimeService::WorkerThread::SetWorker(WorkerPrivate* aWorkerPrivate)
{
MOZ_ASSERT(PR_GetCurrentThread() == mThread);
MOZ_ASSERT_IF(aWorkerPrivate, !mWorkerPrivate);
MOZ_ASSERT_IF(!aWorkerPrivate, mWorkerPrivate);
// No need to lock here because mWorkerPrivate is only modified on mThread.
if (mWorkerPrivate) {
MOZ_ASSERT(mObserver);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(RemoveObserver(mObserver)));
mObserver = nullptr;
mWorkerPrivate->SetThread(nullptr);
}
mWorkerPrivate = aWorkerPrivate;
if (mWorkerPrivate) {
mWorkerPrivate->SetThread(this);
nsRefPtr<Observer> observer = new Observer(mWorkerPrivate);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(AddObserver(observer)));
mObserver.swap(observer);
}
}
NS_IMPL_ISUPPORTS_INHERITED0(RuntimeService::WorkerThread, nsThread)
NS_IMETHODIMP
RuntimeService::WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
{
// May be called on any thread!
#ifdef DEBUG
if (PR_GetCurrentThread() == mThread) {
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
}
else if (aRunnable && !IsAcceptingNonWorkerRunnables()) {
// Only enforce cancelable runnables after we've started the worker loop.
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(aRunnable);
MOZ_ASSERT(cancelable,
"Should have been wrapped by the worker's event target!");
}
#endif
// Workers only support asynchronous dispatch for now.
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
return NS_ERROR_UNEXPECTED;
}
nsIRunnable* runnableToDispatch;
nsRefPtr<WorkerRunnable> workerRunnable;
if (aRunnable && PR_GetCurrentThread() == mThread) {
// No need to lock here because mWorkerPrivate is only modified on mThread.
workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(aRunnable);
runnableToDispatch = workerRunnable;
}
else {
runnableToDispatch = aRunnable;
}
nsresult rv = nsThread::Dispatch(runnableToDispatch, NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
NS_IMPL_ISUPPORTS1(RuntimeService::WorkerThread::Observer, nsIThreadObserver)
NS_IMETHODIMP
RuntimeService::WorkerThread::Observer::OnDispatchedEvent(
nsIThreadInternal* /*aThread */)
{
MOZ_ASSUME_UNREACHABLE("This should never be called!");
}
NS_IMETHODIMP
RuntimeService::WorkerThread::Observer::OnProcessNextEvent(
nsIThreadInternal* /* aThread */,
bool aMayWait,
uint32_t aRecursionDepth)
{
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(!aMayWait);
mWorkerPrivate->OnProcessNextEvent(aRecursionDepth);
return NS_OK;
}
NS_IMETHODIMP
RuntimeService::WorkerThread::Observer::AfterProcessNextEvent(
nsIThreadInternal* /* aThread */,
uint32_t aRecursionDepth,
bool /* aEventWasProcessed */)
{
mWorkerPrivate->AssertIsOnWorkerThread();
mWorkerPrivate->AfterProcessNextEvent(aRecursionDepth);
return NS_OK;
}
NS_IMPL_ISUPPORTS_INHERITED0(LogViolationDetailsRunnable, nsRunnable)
NS_IMETHODIMP
LogViolationDetailsRunnable::Run()
{
AssertIsOnMainThread();
nsIContentSecurityPolicy* csp = mWorkerPrivate->GetCSP();
if (csp) {
NS_NAMED_LITERAL_STRING(scriptSample,
"Call to eval() or related function blocked by CSP.");
if (mWorkerPrivate->GetReportCSPViolations()) {
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
mFileName, scriptSample, mLineNum,
EmptyString());
}
}
nsRefPtr<MainThreadStopSyncLoopRunnable> response =
new MainThreadStopSyncLoopRunnable(mWorkerPrivate, mSyncLoopTarget.forget(),
true);
MOZ_ALWAYS_TRUE(response->Dispatch(nullptr));
return NS_OK;
}
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable)
NS_IMETHODIMP
WorkerThreadPrimaryRunnable::Run()
{
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
"NuwaMarkCurrentThread is undefined!");
NuwaMarkCurrentThread(nullptr, nullptr);
NuwaFreezeCurrentThread();
}
#endif
char stackBaseGuess;
nsAutoCString threadName;
threadName.AssignLiteral("WebWorker '");
threadName.Append(NS_LossyConvertUTF16toASCII(mWorkerPrivate->ScriptURL()));
threadName.Append('\'');
profiler_register_thread(threadName.get(), &stackBaseGuess);
mThread->SetWorker(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
{
nsCycleCollector_startup();
WorkerJSRuntime runtime(mWorkerPrivate);
JSRuntime* rt = runtime.Runtime();
JSContext* cx = CreateJSContextForWorker(mWorkerPrivate, rt);
if (!cx) {
// XXX need to fire an error at parent.
NS_ERROR("Failed to create runtime and context!");
return NS_ERROR_FAILURE;
}
{
#ifdef MOZ_ENABLE_PROFILER_SPS
PseudoStack* stack = mozilla_get_pseudo_stack();
if (stack) {
stack->sampleRuntime(rt);
}
#endif
{
JSAutoRequest ar(cx);
mWorkerPrivate->DoRunLoop(cx);
JS_ReportPendingException(cx);
}
#ifdef MOZ_ENABLE_PROFILER_SPS
if (stack) {
stack->sampleRuntime(nullptr);
}
#endif
}
// Destroy the main context. This will unroot the main worker global and
// GC. This is not the last JSContext (WorkerJSRuntime maintains an
// internal JSContext).
JS_DestroyContext(cx);
// Now WorkerJSRuntime goes out of scope and its destructor will shut
// down the cycle collector and destroy the final JSContext. This
// breaks any remaining cycles and collects the C++ and JS objects
// participating.
}
mThread->SetWorker(nullptr);
mWorkerPrivate->ScheduleDeletion();
// It is no longer safe to touch mWorkerPrivate.
mWorkerPrivate = nullptr;
// Now recycle this thread.
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
nsRefPtr<FinishedRunnable> finishedRunnable =
new FinishedRunnable(mThread.forget());
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mainThread->Dispatch(finishedRunnable,
NS_DISPATCH_NORMAL)));
profiler_unregister_thread();
return NS_OK;
}
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable,
nsRunnable)
NS_IMETHODIMP
WorkerThreadPrimaryRunnable::FinishedRunnable::Run()
{
AssertIsOnMainThread();
nsRefPtr<RuntimeService::WorkerThread> thread;
mThread.swap(thread);
RuntimeService* rts = RuntimeService::GetService();
if (rts) {
rts->NoteIdleThread(thread);
}
else if (thread->ShutdownRequired()) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->Shutdown()));
}
return NS_OK;
}

Просмотреть файл

@ -11,18 +11,13 @@
#include "nsIObserver.h"
#include "mozilla/Attributes.h"
#include "mozilla/Mutex.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsAutoPtr.h"
#include "nsClassHashtable.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsHashKeys.h"
#include "nsString.h"
#include "nsTArray.h"
class nsIRunnable;
class nsIThread;
class nsITimer;
class nsPIDOMWindow;
@ -34,6 +29,10 @@ class WorkerPrivate;
class RuntimeService MOZ_FINAL : public nsIObserver
{
public:
class WorkerThread;
private:
struct SharedWorkerInfo
{
WorkerPrivate* mWorkerPrivate;
@ -68,7 +67,7 @@ class RuntimeService MOZ_FINAL : public nsIObserver
struct IdleThreadInfo
{
nsCOMPtr<nsIThread> mThread;
nsRefPtr<WorkerThread> mThread;
mozilla::TimeStamp mExpirationTime;
};
@ -173,7 +172,7 @@ public:
}
void
NoteIdleThread(nsIThread* aThread);
NoteIdleThread(WorkerThread* aThread);
static void
GetDefaultJSSettings(JSSettings& aSettings)

Просмотреть файл

@ -35,6 +35,7 @@
#include "Principal.h"
#include "WorkerFeature.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#define MAX_CONCURRENT_SCRIPTS 1000
@ -131,8 +132,6 @@ ChannelFromScriptURL(nsIPrincipal* principal,
return rv;
}
class ScriptLoaderRunnable;
struct ScriptLoadInfo
{
ScriptLoadInfo()
@ -155,7 +154,9 @@ struct ScriptLoadInfo
bool mExecutionResult;
};
class ScriptExecutorRunnable : public WorkerSyncRunnable
class ScriptLoaderRunnable;
class ScriptExecutorRunnable MOZ_FINAL : public MainThreadWorkerSyncRunnable
{
ScriptLoaderRunnable& mScriptLoader;
uint32_t mFirstIndex;
@ -163,38 +164,29 @@ class ScriptExecutorRunnable : public WorkerSyncRunnable
public:
ScriptExecutorRunnable(ScriptLoaderRunnable& aScriptLoader,
uint32_t aSyncQueueKey, uint32_t aFirstIndex,
nsIEventTarget* aSyncLoopTarget, uint32_t aFirstIndex,
uint32_t aLastIndex);
bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
AssertIsOnMainThread();
return true;
}
private:
~ScriptExecutorRunnable()
{ }
void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{
AssertIsOnMainThread();
}
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
void
PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
virtual void
PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult)
MOZ_OVERRIDE;
};
class ScriptLoaderRunnable : public WorkerFeature,
public nsIRunnable,
public nsIStreamLoaderObserver
class ScriptLoaderRunnable MOZ_FINAL : public WorkerFeature,
public nsIRunnable,
public nsIStreamLoaderObserver
{
friend class ScriptExecutorRunnable;
WorkerPrivate* mWorkerPrivate;
uint32_t mSyncQueueKey;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
nsTArray<ScriptLoadInfo> mLoadInfos;
bool mIsWorkerScript;
bool mCanceled;
@ -204,21 +196,26 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
ScriptLoaderRunnable(WorkerPrivate* aWorkerPrivate,
uint32_t aSyncQueueKey,
nsIEventTarget* aSyncLoopTarget,
nsTArray<ScriptLoadInfo>& aLoadInfos,
bool aIsWorkerScript)
: mWorkerPrivate(aWorkerPrivate), mSyncQueueKey(aSyncQueueKey),
: mWorkerPrivate(aWorkerPrivate), mSyncLoopTarget(aSyncLoopTarget),
mIsWorkerScript(aIsWorkerScript), mCanceled(false),
mCanceledMainThread(false)
{
aWorkerPrivate->AssertIsOnWorkerThread();
NS_ASSERTION(!aIsWorkerScript || aLoadInfos.Length() == 1, "Bad args!");
MOZ_ASSERT(aSyncLoopTarget);
MOZ_ASSERT_IF(aIsWorkerScript, aLoadInfos.Length() == 1);
mLoadInfos.SwapElements(aLoadInfos);
}
private:
~ScriptLoaderRunnable()
{ }
NS_IMETHOD
Run()
Run() MOZ_OVERRIDE
{
AssertIsOnMainThread();
@ -232,7 +229,7 @@ public:
NS_IMETHOD
OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
nsresult aStatus, uint32_t aStringLen,
const uint8_t* aString)
const uint8_t* aString) MOZ_OVERRIDE
{
AssertIsOnMainThread();
@ -256,8 +253,8 @@ public:
return NS_OK;
}
bool
Notify(JSContext* aCx, Status aStatus)
virtual bool
Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE
{
mWorkerPrivate->AssertIsOnWorkerThread();
@ -587,9 +584,10 @@ public:
if (firstIndex != UINT32_MAX && lastIndex != UINT32_MAX) {
nsRefPtr<ScriptExecutorRunnable> runnable =
new ScriptExecutorRunnable(*this, mSyncQueueKey, firstIndex, lastIndex);
new ScriptExecutorRunnable(*this, mSyncLoopTarget, firstIndex,
lastIndex);
if (!runnable->Dispatch(nullptr)) {
NS_ERROR("This should never fail!");
MOZ_ASSERT(false, "This should never fail!");
}
}
}
@ -597,45 +595,26 @@ public:
NS_IMPL_ISUPPORTS2(ScriptLoaderRunnable, nsIRunnable, nsIStreamLoaderObserver)
class StopSyncLoopRunnable MOZ_FINAL : public MainThreadSyncRunnable
{
public:
StopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate,
uint32_t aSyncQueueKey)
: MainThreadSyncRunnable(aWorkerPrivate, SkipWhenClearing, aSyncQueueKey,
false)
{ }
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
aWorkerPrivate->AssertIsOnWorkerThread();
aWorkerPrivate->StopSyncLoop(mSyncQueueKey, true);
return true;
}
};
class ChannelGetterRunnable MOZ_FINAL : public nsRunnable
{
WorkerPrivate* mParentWorker;
uint32_t mSyncQueueKey;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
const nsAString& mScriptURL;
nsIChannel** mChannel;
nsresult mResult;
public:
ChannelGetterRunnable(WorkerPrivate* aParentWorker,
uint32_t aSyncQueueKey,
nsIEventTarget* aSyncLoopTarget,
const nsAString& aScriptURL,
nsIChannel** aChannel)
: mParentWorker(aParentWorker), mSyncQueueKey(aSyncQueueKey),
: mParentWorker(aParentWorker), mSyncLoopTarget(aSyncLoopTarget),
mScriptURL(aScriptURL), mChannel(aChannel), mResult(NS_ERROR_FAILURE)
{
aParentWorker->AssertIsOnWorkerThread();
MOZ_ASSERT(aSyncLoopTarget);
}
virtual ~ChannelGetterRunnable() { }
NS_IMETHOD
Run() MOZ_OVERRIDE
{
@ -660,8 +639,9 @@ public:
channel.forget(mChannel);
}
nsRefPtr<StopSyncLoopRunnable> runnable =
new StopSyncLoopRunnable(mParentWorker, mSyncQueueKey);
nsRefPtr<MainThreadStopSyncLoopRunnable> runnable =
new MainThreadStopSyncLoopRunnable(mParentWorker,
mSyncLoopTarget.forget(), true);
if (!runnable->Dispatch(nullptr)) {
NS_ERROR("This should never fail!");
}
@ -675,19 +655,21 @@ public:
return mResult;
}
private:
virtual ~ChannelGetterRunnable()
{ }
};
ScriptExecutorRunnable::ScriptExecutorRunnable(
ScriptLoaderRunnable& aScriptLoader,
uint32_t aSyncQueueKey,
nsIEventTarget* aSyncLoopTarget,
uint32_t aFirstIndex,
uint32_t aLastIndex)
: WorkerSyncRunnable(aScriptLoader.mWorkerPrivate, aSyncQueueKey),
: MainThreadWorkerSyncRunnable(aScriptLoader.mWorkerPrivate, aSyncLoopTarget),
mScriptLoader(aScriptLoader), mFirstIndex(aFirstIndex), mLastIndex(aLastIndex)
{
NS_ASSERTION(aFirstIndex <= aLastIndex, "Bad first index!");
NS_ASSERTION(aLastIndex < aScriptLoader.mLoadInfos.Length(),
"Bad last index!");
MOZ_ASSERT(aFirstIndex <= aLastIndex);
MOZ_ASSERT(aLastIndex < aScriptLoader.mLoadInfos.Length());
}
bool
@ -759,7 +741,7 @@ ScriptExecutorRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
}
aWorkerPrivate->RemoveFeature(aCx, &mScriptLoader);
aWorkerPrivate->StopSyncLoop(mSyncQueueKey, result);
aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, result);
}
}
@ -773,7 +755,7 @@ LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
AutoSyncLoopHolder syncLoop(aWorkerPrivate);
nsRefPtr<ScriptLoaderRunnable> loader =
new ScriptLoaderRunnable(aWorkerPrivate, syncLoop.SyncQueueKey(),
new ScriptLoaderRunnable(aWorkerPrivate, syncLoop.EventTarget(),
aLoadInfos, aIsWorkerScript);
NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
@ -789,7 +771,7 @@ LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
return false;
}
return syncLoop.RunAndForget(aCx);
return syncLoop.Run();
}
} /* anonymous namespace */
@ -832,15 +814,15 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx,
AutoSyncLoopHolder syncLoop(aParent);
nsRefPtr<ChannelGetterRunnable> getter =
new ChannelGetterRunnable(aParent, syncLoop.SyncQueueKey(),
aScriptURL, aChannel);
new ChannelGetterRunnable(aParent, syncLoop.EventTarget(), aScriptURL,
aChannel);
if (NS_FAILED(NS_DispatchToMainThread(getter, NS_DISPATCH_NORMAL))) {
NS_ERROR("Failed to dispatch!");
return NS_ERROR_FAILURE;
}
if (!syncLoop.RunAndForget(aCx)) {
if (!syncLoop.Run()) {
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -4,24 +4,24 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "URL.h"
#include "File.h"
#include "WorkerPrivate.h"
#include "nsThreadUtils.h"
#include "nsPIDOMWindow.h"
#include "nsGlobalWindow.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsServiceManagerUtils.h"
#include "nsIDocument.h"
#include "nsIDOMFile.h"
#include "nsIIOService.h"
#include "nsPIDOMWindow.h"
#include "mozilla/dom/URL.h"
#include "mozilla/dom/URLBinding.h"
#include "mozilla/dom/URLSearchParams.h"
#include "nsIIOService.h"
#include "nsGlobalWindow.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsNetCID.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "File.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
BEGIN_WORKERS_NAMESPACE
using mozilla::dom::GlobalObject;
@ -67,43 +67,7 @@ class URLRunnable : public nsRunnable
{
protected:
WorkerPrivate* mWorkerPrivate;
uint32_t mSyncQueueKey;
private:
class ResponseRunnable : public WorkerSyncRunnable
{
uint32_t mSyncQueueKey;
public:
ResponseRunnable(WorkerPrivate* aWorkerPrivate,
uint32_t aSyncQueueKey)
: WorkerSyncRunnable(aWorkerPrivate, aSyncQueueKey, false),
mSyncQueueKey(aSyncQueueKey)
{
NS_ASSERTION(aWorkerPrivate, "Don't hand me a null WorkerPrivate!");
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
aWorkerPrivate->StopSyncLoop(mSyncQueueKey, true);
return true;
}
bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
AssertIsOnMainThread();
return true;
}
void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{
AssertIsOnMainThread();
}
};
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
protected:
URLRunnable(WorkerPrivate* aWorkerPrivate)
@ -117,15 +81,17 @@ public:
Dispatch(JSContext* aCx)
{
mWorkerPrivate->AssertIsOnWorkerThread();
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
mSyncQueueKey = syncLoop.SyncQueueKey();
mSyncLoopTarget = syncLoop.EventTarget();
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
JS_ReportError(aCx, "Failed to dispatch to main thread!");
return false;
}
return syncLoop.RunAndForget(aCx);
return syncLoop.Run();
}
private:
@ -135,8 +101,10 @@ private:
MainThreadRun();
nsRefPtr<ResponseRunnable> response =
new ResponseRunnable(mWorkerPrivate, mSyncQueueKey);
nsRefPtr<MainThreadStopSyncLoopRunnable> response =
new MainThreadStopSyncLoopRunnable(mWorkerPrivate,
mSyncLoopTarget.forget(),
true);
if (!response->Dispatch(nullptr)) {
NS_WARNING("Failed to dispatch response!");
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -9,25 +9,19 @@
#include "Workers.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIRunnable.h"
#include "nsIThread.h"
#include "nsIThreadInternal.h"
#include "nsPIDOMWindow.h"
#include "mozilla/Assertions.h"
#include "mozilla/CondVar.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDataHashtable.h"
#include "nsDOMEventTargetHelper.h"
#include "nsEventQueue.h"
#include "nsHashKeys.h"
#include "nsRefPtrHashtable.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "nsTPriorityQueue.h"
#include "StructuredCloneTags.h"
#include "Queue.h"
@ -36,8 +30,10 @@
class JSAutoStructuredCloneBuffer;
class nsIChannel;
class nsIDocument;
class nsIEventTarget;
class nsIPrincipal;
class nsIScriptContext;
class nsIThread;
class nsITimer;
class nsIURI;
@ -51,142 +47,19 @@ class Function;
}
}
BEGIN_WORKERS_NAMESPACE
class MessagePort;
class SharedWorker;
class WorkerGlobalScope;
class WorkerPrivate;
class WorkerRunnable : public nsIRunnable
{
public:
enum Target { ParentThread, WorkerThread };
enum BusyBehavior { ModifyBusyCount, UnchangedBusyCount };
enum ClearingBehavior { SkipWhenClearing, RunWhenClearing };
protected:
WorkerPrivate* mWorkerPrivate;
Target mTarget;
BusyBehavior mBusyBehavior;
ClearingBehavior mClearingBehavior;
public:
NS_DECL_THREADSAFE_ISUPPORTS
bool
Dispatch(JSContext* aCx);
static bool
DispatchToMainThread(nsIRunnable*);
bool
WantsToRunDuringClear()
{
return mClearingBehavior == RunWhenClearing;
}
protected:
WorkerRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget,
BusyBehavior aBusyBehavior,
ClearingBehavior aClearingBehavior)
#ifdef DEBUG
;
#else
: mWorkerPrivate(aWorkerPrivate), mTarget(aTarget),
mBusyBehavior(aBusyBehavior), mClearingBehavior(aClearingBehavior)
{ }
struct PRThread;
#endif
virtual ~WorkerRunnable()
{ }
BEGIN_WORKERS_NAMESPACE
virtual bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
virtual void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult);
virtual bool
DispatchInternal();
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
virtual void
PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
public:
NS_DECL_NSIRUNNABLE
};
class WorkerSyncRunnable : public WorkerRunnable
{
protected:
uint32_t mSyncQueueKey;
bool mBypassSyncQueue;
protected:
friend class WorkerPrivate;
WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, uint32_t aSyncQueueKey,
bool aBypassSyncQueue = false,
ClearingBehavior aClearingBehavior = SkipWhenClearing)
: WorkerRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount,
aClearingBehavior),
mSyncQueueKey(aSyncQueueKey), mBypassSyncQueue(aBypassSyncQueue)
{ }
virtual ~WorkerSyncRunnable()
{ }
virtual bool
DispatchInternal() MOZ_OVERRIDE;
};
class MainThreadSyncRunnable : public WorkerSyncRunnable
{
public:
MainThreadSyncRunnable(WorkerPrivate* aWorkerPrivate,
ClearingBehavior aClearingBehavior,
uint32_t aSyncQueueKey,
bool aBypassSyncEventQueue)
: WorkerSyncRunnable(aWorkerPrivate, aSyncQueueKey, aBypassSyncEventQueue,
aClearingBehavior)
{
AssertIsOnMainThread();
}
bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
AssertIsOnMainThread();
return true;
}
void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) MOZ_OVERRIDE
{
AssertIsOnMainThread();
}
};
class WorkerControlRunnable : public WorkerRunnable
{
protected:
WorkerControlRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget,
BusyBehavior aBusyBehavior)
: WorkerRunnable(aWorkerPrivate, aTarget, aBusyBehavior, SkipWhenClearing)
{ }
virtual ~WorkerControlRunnable()
{ }
virtual bool
DispatchInternal() MOZ_OVERRIDE;
};
class AutoSyncLoopHolder;
class MessagePort;
class SharedWorker;
class WorkerControlRunnable;
class WorkerGlobalScope;
class WorkerPrivate;
class WorkerRunnable;
// SharedMutex is a small wrapper around an (internal) reference-counted Mutex
// object. It exists to avoid changing a lot of code to use Mutex* instead of
@ -195,7 +68,7 @@ class SharedMutex
{
typedef mozilla::Mutex Mutex;
class RefCountedMutex : public Mutex
class RefCountedMutex MOZ_FINAL : public Mutex
{
public:
RefCountedMutex(const char* aName)
@ -222,20 +95,17 @@ public:
operator Mutex&()
{
MOZ_ASSERT(mMutex);
return *mMutex;
}
operator const Mutex&() const
{
MOZ_ASSERT(mMutex);
return *mMutex;
}
void
AssertCurrentThreadOwns() const
{
MOZ_ASSERT(mMutex);
mMutex->AssertCurrentThreadOwns();
}
};
@ -245,6 +115,10 @@ class WorkerPrivateParent : public nsDOMEventTargetHelper
{
class SynchronizeAndResumeRunnable;
protected:
class EventTarget;
friend class EventTarget;
public:
struct LocationInfo
{
@ -312,6 +186,10 @@ protected:
mozilla::CondVar mCondVar;
mozilla::CondVar mMemoryReportCondVar;
// Protected by mMutex.
nsRefPtr<EventTarget> mEventTarget;
nsTArray<nsRefPtr<WorkerRunnable>> mPreStartRunnables;
private:
WorkerPrivate* mParent;
nsString mScriptURL;
@ -322,7 +200,7 @@ private:
LoadInfo mLoadInfo;
// Only used for top level workers.
nsTArray<nsRefPtr<WorkerRunnable> > mQueuedRunnables;
nsTArray<nsCOMPtr<nsIRunnable>> mQueuedRunnables;
nsRevocableEventPtr<SynchronizeAndResumeRunnable> mSynchronizeRunnable;
// Only for ChromeWorkers without window and only touched on the main thread.
@ -376,6 +254,9 @@ private:
bool aToMessagePort, uint64_t aMessagePortSerial,
ErrorResult& aRv);
nsresult
DispatchPrivate(WorkerRunnable* aRunnable, nsIEventTarget* aSyncLoopTarget);
public:
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
@ -384,6 +265,21 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent,
nsDOMEventTargetHelper)
nsresult
Dispatch(WorkerRunnable* aRunnable)
{
return DispatchPrivate(aRunnable, nullptr);
}
nsresult
DispatchControlRunnable(WorkerControlRunnable* aWorkerControlRunnable);
already_AddRefed<WorkerRunnable>
MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable);
already_AddRefed<nsIEventTarget>
GetEventTarget();
// May be called on any thread...
bool
Start();
@ -515,7 +411,7 @@ public:
WorkerScriptLoaded();
void
QueueRunnable(WorkerRunnable* aRunnable)
QueueRunnable(nsIRunnable* aRunnable)
{
AssertIsOnMainThread();
mQueuedRunnables.AppendElement(aRunnable);
@ -538,13 +434,10 @@ public:
IsAcceptingEvents()
{
AssertIsOnParentThread();
bool acceptingEvents;
{
mozilla::MutexAutoLock lock(mMutex);
acceptingEvents = mParentStatus < Terminating;
MutexAutoLock lock(mMutex);
return mParentStatus < Terminating;
}
return acceptingEvents;
}
Status
ParentStatus() const
@ -775,53 +668,62 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
{
friend class WorkerPrivateParent<WorkerPrivate>;
typedef WorkerPrivateParent<WorkerPrivate> ParentType;
friend class AutoSyncLoopHolder;
struct TimeoutInfo;
typedef Queue<WorkerRunnable*, 50> EventQueue;
EventQueue mQueue;
EventQueue mControlQueue;
struct SyncQueue
{
Queue<WorkerRunnable*, 10> mQueue;
bool mComplete;
bool mResult;
SyncQueue()
: mComplete(false), mResult(false)
{ }
~SyncQueue()
{
WorkerRunnable* event;
while (mQueue.Pop(event)) {
event->Release();
}
}
};
class MemoryReporter;
friend class MemoryReporter;
nsTArray<nsAutoPtr<SyncQueue> > mSyncQueues;
enum GCTimerMode
{
PeriodicTimer = 0,
IdleTimer,
NoTimer
};
Queue<WorkerControlRunnable*, 4> mControlQueue;
// Touched on multiple threads, protected with mMutex.
JSContext* mJSContext;
nsRefPtr<WorkerCrossThreadDispatcher> mCrossThreadDispatcher;
nsTArray<nsCOMPtr<nsIRunnable>> mUndispatchedRunnablesForSyncLoop;
nsCOMPtr<nsIThread> mThread;
// Things touched on worker thread only.
nsRefPtr<WorkerGlobalScope> mScope;
nsTArray<ParentType*> mChildWorkers;
nsTArray<WorkerFeature*> mFeatures;
nsTArray<nsAutoPtr<TimeoutInfo> > mTimeouts;
nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts;
struct SyncLoopInfo
{
SyncLoopInfo(EventTarget* aEventTarget);
nsRefPtr<EventTarget> mEventTarget;
bool mCompleted;
bool mResult;
#ifdef DEBUG
bool mHasRun;
#endif
};
// This is only modified on the worker thread, but in DEBUG builds
// AssertValidSyncLoop function iterates it on other threads. Therefore
// modifications are done with mMutex held *only* in DEBUG builds.
nsTArray<nsAutoPtr<SyncLoopInfo>> mSyncLoopStack;
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsITimer> mGCTimer;
nsCOMPtr<nsIEventTarget> mPeriodicGCTimerTarget;
nsCOMPtr<nsIEventTarget> mIdleGCTimerTarget;
nsRefPtr<MemoryReporter> mMemoryReporter;
nsRefPtrHashtable<nsUint64HashKey, MessagePort> mWorkerPorts;
mozilla::TimeStamp mKillTime;
TimeStamp mKillTime;
uint32_t mErrorHandlerRecursionCount;
uint32_t mNextTimeoutId;
Status mStatus;
@ -832,9 +734,11 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
bool mCloseHandlerFinished;
bool mMemoryReporterRunning;
bool mBlockedForMemoryReporter;
bool mCancelAllPendingRunnables;
bool mPeriodicGCTimerRunning;
#ifdef DEBUG
nsCOMPtr<nsIThread> mThread;
PRThread* mPRThread;
#endif
bool mPreferences[WORKERPREF_COUNT];
@ -867,27 +771,8 @@ public:
bool
OperationCallback(JSContext* aCx);
bool
Dispatch(WorkerRunnable* aEvent)
{
return Dispatch(aEvent, &mQueue);
}
bool
Dispatch(WorkerSyncRunnable* aEvent)
{
if (aEvent->mBypassSyncQueue) {
return Dispatch(aEvent, &mQueue);
}
return DispatchToSyncQueue(aEvent);
}
bool
Dispatch(WorkerControlRunnable* aEvent)
{
return Dispatch(aEvent, &mControlQueue);
}
nsresult
IsOnCurrentThread(bool* aIsOnCurrentThread);
bool
CloseInternal(JSContext* aCx)
@ -930,18 +815,6 @@ public:
mFeatures.IsEmpty());
}
uint32_t
CreateNewSyncLoop();
bool
RunSyncLoop(JSContext* aCx, uint32_t aSyncLoopKey);
void
StopSyncLoop(uint32_t aSyncLoopKey, bool aSyncResult);
void
DestroySyncLoop(uint32_t aSyncLoopKey);
void
PostMessageToParent(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
@ -1008,7 +881,7 @@ public:
UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, uint32_t aValue);
void
ScheduleDeletion(bool aWasPending);
ScheduleDeletion();
bool
BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats);
@ -1042,18 +915,14 @@ public:
return mScope;
}
#ifdef DEBUG
void
AssertIsOnWorkerThread() const;
SetThread(nsIThread* aThread);
void
SetThread(nsIThread* aThread)
{
mThread = aThread;
}
#else
void
AssertIsOnWorkerThread() const
#ifdef DEBUG
;
#else
{ }
#endif
@ -1113,20 +982,37 @@ public:
return mPreferences[WORKERPREF_PROMISE];
}
void
StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult);
bool
AllPendingRunnablesShouldBeCanceled() const
{
return mCancelAllPendingRunnables;
}
void
OnProcessNextEvent(uint32_t aRecursionDepth);
void
AfterProcessNextEvent(uint32_t aRecursionDepth);
void
AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget)
#ifdef DEBUG
;
#else
{ }
#endif
private:
WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
const nsAString& aScriptURL, bool aIsChromeWorker,
WorkerType aWorkerType, const nsAString& aSharedWorkerName,
LoadInfo& aLoadInfo);
bool
Dispatch(WorkerRunnable* aEvent, EventQueue* aQueue);
bool
DispatchToSyncQueue(WorkerSyncRunnable* aEvent);
void
ClearQueue(EventQueue* aQueue);
ClearMainEventQueue();
bool
MayContinueRunning()
@ -1135,7 +1021,7 @@ private:
Status status;
{
mozilla::MutexAutoLock lock(mMutex);
MutexAutoLock lock(mMutex);
status = mStatus;
}
@ -1157,22 +1043,15 @@ private:
bool
ScheduleKillCloseEventRunnable(JSContext* aCx);
void
StopAcceptingEvents()
bool
ProcessAllControlRunnables()
{
AssertIsOnWorkerThread();
mozilla::MutexAutoLock lock(mMutex);
mStatus = Dead;
mJSContext = nullptr;
ClearQueue(&mControlQueue);
ClearQueue(&mQueue);
MutexAutoLock lock(mMutex);
return ProcessAllControlRunnablesLocked();
}
bool
ProcessAllControlRunnables();
ProcessAllControlRunnablesLocked();
void
EnableMemoryReporter();
@ -1197,6 +1076,21 @@ private:
AssertIsOnWorkerThread();
memcpy(aPreferences, mPreferences, WORKERPREF_COUNT * sizeof(bool));
}
already_AddRefed<nsIEventTarget>
CreateNewSyncLoop();
bool
RunCurrentSyncLoop();
void
InitializeGCTimers();
void
SetGCTimerMode(GCTimerMode aMode);
void
ShutdownGCTimers();
};
// This class is only used to trick the DOM bindings. We never create
@ -1246,38 +1140,40 @@ ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime);
class AutoSyncLoopHolder
{
WorkerPrivate* mWorkerPrivate;
nsCOMPtr<nsIEventTarget> mTarget;
public:
AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate)
: mWorkerPrivate(aWorkerPrivate), mSyncLoopKey(UINT32_MAX)
: mWorkerPrivate(aWorkerPrivate), mTarget(aWorkerPrivate->CreateNewSyncLoop())
{
mSyncLoopKey = mWorkerPrivate->CreateNewSyncLoop();
aWorkerPrivate->AssertIsOnWorkerThread();
}
~AutoSyncLoopHolder()
{
if (mWorkerPrivate) {
mWorkerPrivate->StopSyncLoop(mSyncLoopKey, false);
mWorkerPrivate->DestroySyncLoop(mSyncLoopKey);
mWorkerPrivate->AssertIsOnWorkerThread();
mWorkerPrivate->StopSyncLoop(mTarget, false);
}
}
bool
RunAndForget(JSContext* aCx)
Run()
{
WorkerPrivate* workerPrivate = mWorkerPrivate;
mWorkerPrivate = nullptr;
return workerPrivate->RunSyncLoop(aCx, mSyncLoopKey);
workerPrivate->AssertIsOnWorkerThread();
return workerPrivate->RunCurrentSyncLoop();
}
uint32_t
SyncQueueKey() const
nsIEventTarget*
EventTarget() const
{
return mSyncLoopKey;
return mTarget;
}
private:
WorkerPrivate* mWorkerPrivate;
uint32_t mSyncLoopKey;
};
END_WORKERS_NAMESPACE

Просмотреть файл

@ -0,0 +1,480 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* 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 "WorkerRunnable.h"
#include "nsIEventTarget.h"
#include "nsIRunnable.h"
#include "js/RootingAPI.h"
#include "js/Value.h"
#include "nsThreadUtils.h"
#include "WorkerPrivate.h"
USING_WORKERS_NAMESPACE
namespace {
const nsIID kWorkerRunnableIID = {
0x320cc0b5, 0xef12, 0x4084, { 0x88, 0x6e, 0xca, 0x6a, 0x81, 0xe4, 0x1d, 0x68 }
};
void
MaybeReportMainThreadException(JSContext* aCx, bool aResult)
{
AssertIsOnMainThread();
if (aCx && !aResult) {
JS_ReportPendingException(aCx);
}
}
} // anonymous namespace
#ifdef DEBUG
WorkerRunnable::WorkerRunnable(WorkerPrivate* aWorkerPrivate,
TargetAndBusyBehavior aBehavior)
: mWorkerPrivate(aWorkerPrivate), mBehavior(aBehavior), mCanceled(0),
mCallingCancelWithinRun(false)
{
MOZ_ASSERT(aWorkerPrivate);
}
#endif
bool
WorkerRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
#ifdef DEBUG
MOZ_ASSERT(aWorkerPrivate);
switch (mBehavior) {
case ParentThreadUnchangedBusyCount:
aWorkerPrivate->AssertIsOnWorkerThread();
break;
case WorkerThreadModifyBusyCount:
aWorkerPrivate->AssertIsOnParentThread();
MOZ_ASSERT(aCx);
break;
case WorkerThreadUnchangedBusyCount:
aWorkerPrivate->AssertIsOnParentThread();
break;
default:
MOZ_ASSUME_UNREACHABLE("Unknown behavior!");
}
#endif
if (mBehavior == WorkerThreadModifyBusyCount) {
return aWorkerPrivate->ModifyBusyCount(aCx, true);
}
return true;
}
bool
WorkerRunnable::Dispatch(JSContext* aCx)
{
bool ok;
if (!aCx) {
ok = PreDispatch(nullptr, mWorkerPrivate);
if (ok) {
ok = DispatchInternal();
}
PostDispatch(nullptr, mWorkerPrivate, ok);
return ok;
}
JSAutoRequest ar(aCx);
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
Maybe<JSAutoCompartment> ac;
if (global) {
ac.construct(aCx, global);
}
ok = PreDispatch(aCx, mWorkerPrivate);
if (ok && !DispatchInternal()) {
ok = false;
}
PostDispatch(aCx, mWorkerPrivate, ok);
return ok;
}
bool
WorkerRunnable::DispatchInternal()
{
if (mBehavior == WorkerThreadModifyBusyCount ||
mBehavior == WorkerThreadUnchangedBusyCount) {
return NS_SUCCEEDED(mWorkerPrivate->Dispatch(this));
}
MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount);
if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
return NS_SUCCEEDED(parent->Dispatch(this));
}
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
return NS_SUCCEEDED(mainThread->Dispatch(this, NS_DISPATCH_NORMAL));
}
void
WorkerRunnable::PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{
MOZ_ASSERT(aWorkerPrivate);
#ifdef DEBUG
switch (mBehavior) {
case ParentThreadUnchangedBusyCount:
aWorkerPrivate->AssertIsOnWorkerThread();
break;
case WorkerThreadModifyBusyCount:
aWorkerPrivate->AssertIsOnParentThread();
MOZ_ASSERT(aCx);
break;
case WorkerThreadUnchangedBusyCount:
aWorkerPrivate->AssertIsOnParentThread();
break;
default:
MOZ_ASSUME_UNREACHABLE("Unknown behavior!");
}
#endif
if (!aDispatchResult) {
if (mBehavior == WorkerThreadModifyBusyCount) {
aWorkerPrivate->ModifyBusyCount(aCx, false);
}
if (aCx) {
JS_ReportPendingException(aCx);
}
}
}
void
WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aRunResult)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aWorkerPrivate);
#ifdef DEBUG
switch (mBehavior) {
case ParentThreadUnchangedBusyCount:
aWorkerPrivate->AssertIsOnParentThread();
break;
case WorkerThreadModifyBusyCount:
aWorkerPrivate->AssertIsOnWorkerThread();
break;
case WorkerThreadUnchangedBusyCount:
aWorkerPrivate->AssertIsOnWorkerThread();
break;
default:
MOZ_ASSUME_UNREACHABLE("Unknown behavior!");
}
#endif
if (mBehavior == WorkerThreadModifyBusyCount) {
if (!aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false)) {
aRunResult = false;
}
}
if (!aRunResult) {
JS_ReportPendingException(aCx);
}
}
// static
WorkerRunnable*
WorkerRunnable::FromRunnable(nsIRunnable* aRunnable)
{
MOZ_ASSERT(aRunnable);
WorkerRunnable* runnable;
nsresult rv = aRunnable->QueryInterface(kWorkerRunnableIID,
reinterpret_cast<void**>(&runnable));
if (NS_FAILED(rv)) {
return nullptr;
}
MOZ_ASSERT(runnable);
return runnable;
}
NS_IMPL_ADDREF(WorkerRunnable)
NS_IMPL_RELEASE(WorkerRunnable)
NS_INTERFACE_MAP_BEGIN(WorkerRunnable)
NS_INTERFACE_MAP_ENTRY(nsIRunnable)
NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable)
NS_INTERFACE_MAP_ENTRY(nsISupports)
// kWorkerRunnableIID is special in that it does not AddRef its result.
if (aIID.Equals(kWorkerRunnableIID)) {
*aInstancePtr = this;
return NS_OK;
}
else
NS_INTERFACE_MAP_END
NS_IMETHODIMP
WorkerRunnable::Run()
{
bool targetIsWorkerThread = mBehavior == WorkerThreadModifyBusyCount ||
mBehavior == WorkerThreadUnchangedBusyCount;
#ifdef DEBUG
MOZ_ASSERT_IF(mCallingCancelWithinRun, targetIsWorkerThread);
if (targetIsWorkerThread) {
mWorkerPrivate->AssertIsOnWorkerThread();
}
else {
MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount);
mWorkerPrivate->AssertIsOnParentThread();
}
#endif
if (IsCanceled() && !mCallingCancelWithinRun) {
return NS_OK;
}
JSContext* cx;
nsRefPtr<WorkerPrivate> kungFuDeathGrip;
nsCxPusher pusher;
if (targetIsWorkerThread) {
if (mWorkerPrivate->AllPendingRunnablesShouldBeCanceled() &&
!IsCanceled() &&
!mCallingCancelWithinRun) {
// Prevent recursion.
mCallingCancelWithinRun = true;
Cancel();
MOZ_ASSERT(mCallingCancelWithinRun);
mCallingCancelWithinRun = false;
MOZ_ASSERT(IsCanceled(), "Subclass Cancel() didn't set IsCanceled()!");
return NS_OK;
}
cx = mWorkerPrivate->GetJSContext();
MOZ_ASSERT(cx);
}
else {
cx = mWorkerPrivate->ParentJSContext();
MOZ_ASSERT(cx);
kungFuDeathGrip = mWorkerPrivate;
if (!mWorkerPrivate->GetParent()) {
AssertIsOnMainThread();
pusher.Push(cx);
}
}
JSAutoRequest ar(cx);
JS::Rooted<JSObject*> targetCompartmentObject(cx);
if (targetIsWorkerThread) {
targetCompartmentObject = JS::CurrentGlobalOrNull(cx);
} else {
targetCompartmentObject = mWorkerPrivate->GetWrapper();
}
Maybe<JSAutoCompartment> ac;
if (targetCompartmentObject) {
ac.construct(cx, targetCompartmentObject);
}
bool result = WorkerRun(cx, mWorkerPrivate);
// In the case of CompileScriptRunnnable, WorkerRun above can cause us to
// lazily create a global, in which case we need to be in its compartment
// when calling PostRun() below. Maybe<> this time...
if (targetIsWorkerThread &&
ac.empty() &&
js::DefaultObjectForContextOrNull(cx)) {
ac.construct(cx, js::DefaultObjectForContextOrNull(cx));
}
PostRun(cx, mWorkerPrivate, result);
return result ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
WorkerRunnable::Cancel()
{
uint32_t canceledCount = ++mCanceled;
MOZ_ASSERT(canceledCount, "Cancel() overflow!");
// The docs say that Cancel() should not be called more than once and that we
// should throw NS_ERROR_UNEXPECTED if it is.
return (canceledCount == 1) ? NS_OK : NS_ERROR_UNEXPECTED;
}
WorkerSyncRunnable::WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
nsIEventTarget* aSyncLoopTarget)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
mSyncLoopTarget(aSyncLoopTarget)
{
#ifdef DEBUG
if (mSyncLoopTarget) {
mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
}
#endif
}
WorkerSyncRunnable::WorkerSyncRunnable(
WorkerPrivate* aWorkerPrivate,
already_AddRefed<nsIEventTarget> aSyncLoopTarget)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
mSyncLoopTarget(aSyncLoopTarget)
{
#ifdef DEBUG
if (mSyncLoopTarget) {
mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
}
#endif
}
WorkerSyncRunnable::~WorkerSyncRunnable()
{
}
bool
WorkerSyncRunnable::DispatchInternal()
{
if (mSyncLoopTarget) {
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(this, NS_DISPATCH_NORMAL));
}
return WorkerRunnable::DispatchInternal();
}
void
MainThreadWorkerSyncRunnable::PostDispatch(JSContext* aCx,
WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{
MaybeReportMainThreadException(aCx, aDispatchResult);
}
StopSyncLoopRunnable::StopSyncLoopRunnable(
WorkerPrivate* aWorkerPrivate,
already_AddRefed<nsIEventTarget> aSyncLoopTarget,
bool aResult)
: WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget), mResult(aResult)
{
#ifdef DEBUG
mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget);
#endif
}
NS_IMETHODIMP
StopSyncLoopRunnable::Cancel()
{
nsresult rv = Run();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
bool
StopSyncLoopRunnable::WorkerRun(JSContext* aCx,
WorkerPrivate* aWorkerPrivate)
{
aWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(mSyncLoopTarget);
nsCOMPtr<nsIEventTarget> syncLoopTarget;
mSyncLoopTarget.swap(syncLoopTarget);
if (!mResult) {
MaybeSetException(aCx);
}
aWorkerPrivate->StopSyncLoop(syncLoopTarget, mResult);
return true;
}
bool
StopSyncLoopRunnable::DispatchInternal()
{
MOZ_ASSERT(mSyncLoopTarget);
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(this, NS_DISPATCH_NORMAL));
}
void
MainThreadStopSyncLoopRunnable::PostDispatch(JSContext* aCx,
WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{
MaybeReportMainThreadException(aCx, aDispatchResult);
}
#ifdef DEBUG
WorkerControlRunnable::WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
TargetAndBusyBehavior aBehavior)
: WorkerRunnable(aWorkerPrivate, aBehavior)
{
MOZ_ASSERT(aWorkerPrivate);
MOZ_ASSERT(aBehavior == ParentThreadUnchangedBusyCount ||
aBehavior == WorkerThreadUnchangedBusyCount,
"WorkerControlRunnables should not modify the busy count");
}
#endif
bool
WorkerControlRunnable::DispatchInternal()
{
if (mBehavior == WorkerThreadUnchangedBusyCount) {
return NS_SUCCEEDED(mWorkerPrivate->DispatchControlRunnable(this));
}
if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
return NS_SUCCEEDED(parent->DispatchControlRunnable(this));
}
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
return NS_SUCCEEDED(mainThread->Dispatch(this, NS_DISPATCH_NORMAL));
}
void
MainThreadWorkerControlRunnable::PostDispatch(JSContext* aCx,
WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{
AssertIsOnMainThread();
if (aCx && !aDispatchResult) {
JS_ReportPendingException(aCx);
}
}
NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable)

Просмотреть файл

@ -0,0 +1,319 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* 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 mozilla_dom_workers_workerrunnable_h__
#define mozilla_dom_workers_workerrunnable_h__
#include "Workers.h"
#include "nsICancelableRunnable.h"
#include "mozilla/Atomics.h"
#include "nsISupportsImpl.h"
class JSContext;
class nsIEventTarget;
BEGIN_WORKERS_NAMESPACE
class WorkerPrivate;
// Use this runnable to communicate from the worker to its parent or vice-versa.
// The busy count must be taken into consideration and declared at construction
// time.
class WorkerRunnable : public nsICancelableRunnable
{
public:
enum TargetAndBusyBehavior {
// Target the main thread for top-level workers, otherwise target the
// WorkerThread of the worker's parent. No change to the busy count.
ParentThreadUnchangedBusyCount,
// Target the thread where the worker event loop runs. The busy count will
// be incremented before dispatching and decremented (asynchronously) after
// running.
WorkerThreadModifyBusyCount,
// Target the thread where the worker event loop runs. The busy count will
// not be modified in any way. Besides worker-internal runnables this is
// almost always the wrong choice.
WorkerThreadUnchangedBusyCount
};
protected:
// The WorkerPrivate that this runnable is associated with.
WorkerPrivate* mWorkerPrivate;
// See above.
TargetAndBusyBehavior mBehavior;
// It's unclear whether or not Cancel() is supposed to work when called on any
// thread. To be safe we're using an atomic but it's likely overkill.
Atomic<uint32_t> mCanceled;
private:
// Whether or not Cancel() is currently being called from inside the Run()
// method. Avoids infinite recursion when a subclass calls Run() from inside
// Cancel(). Only checked and modified on the target thread.
bool mCallingCancelWithinRun;
public:
NS_DECL_THREADSAFE_ISUPPORTS
// If you override Cancel() then you'll need to either call the base class
// Cancel() method or override IsCanceled() so that the Run() method bails out
// appropriately.
NS_DECL_NSICANCELABLERUNNABLE
// Passing a JSContext here is required for the WorkerThreadModifyBusyCount
// behavior. It also guarantees that any failure (false return) will throw an
// exception on the given context. If a context is not passed then failures
// must be dealt with by the caller.
bool
Dispatch(JSContext* aCx);
// See above note about Cancel().
virtual bool
IsCanceled() const
{
return mCanceled != 0;
}
static WorkerRunnable*
FromRunnable(nsIRunnable* aRunnable);
protected:
WorkerRunnable(WorkerPrivate* aWorkerPrivate, TargetAndBusyBehavior aBehavior)
#ifdef DEBUG
;
#else
: mWorkerPrivate(aWorkerPrivate), mBehavior(aBehavior), mCanceled(0),
mCallingCancelWithinRun(false)
{ }
#endif
// This class is reference counted.
virtual ~WorkerRunnable()
{ }
// By default asserts that Dispatch() is being called on the right thread
// (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
// Also increments the busy count of |mWorkerPrivate| if targeting the
// WorkerThread.
virtual bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
// By default asserts that Dispatch() is being called on the right thread
// (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
// Also reports any Dispatch() failures as an exception on |aCx|, and
// busy count if targeting the WorkerThread and Dispatch() failed.
virtual void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult);
// Must be implemented by subclasses. Called on the target thread.
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
// By default asserts that Run() (and WorkerRun()) were called on the correct
// thread. Any failures (false return from WorkerRun) are reported on |aCx|.
// Also sends an asynchronous message to the ParentThread if the busy
// count was previously modified in PreDispatch().
virtual void
PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
virtual bool
DispatchInternal();
// Calling Run() directly is not supported. Just call Dispatch() and
// WorkerRun() will be called on the correct thread automatically.
NS_DECL_NSIRUNNABLE
};
// This runnable is used to send a message directly to a worker's sync loop.
class WorkerSyncRunnable : public WorkerRunnable
{
protected:
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
// Passing null for aSyncLoopTarget is allowed and will result in the behavior
// of a normal WorkerRunnable.
WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
nsIEventTarget* aSyncLoopTarget);
WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
already_AddRefed<nsIEventTarget> aSyncLoopTarget);
virtual ~WorkerSyncRunnable();
private:
virtual bool
DispatchInternal() MOZ_OVERRIDE;
};
// This runnable is identical to WorkerSyncRunnable except it is meant to be
// used on the main thread only.
class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable
{
protected:
// Passing null for aSyncLoopTarget is allowed and will result in the behavior
// of a normal WorkerRunnable.
MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
nsIEventTarget* aSyncLoopTarget)
: WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget)
{
AssertIsOnMainThread();
}
MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
already_AddRefed<nsIEventTarget> aSyncLoopTarget)
: WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget)
{
AssertIsOnMainThread();
}
virtual ~MainThreadWorkerSyncRunnable()
{ }
private:
virtual bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
AssertIsOnMainThread();
return true;
}
virtual void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) MOZ_OVERRIDE;
};
// This runnable is used to stop a sync loop . As sync loops keep the busy count
// incremented as long as they run this runnable does not modify the busy count
// in any way.
class StopSyncLoopRunnable : public WorkerSyncRunnable
{
bool mResult;
public:
// Passing null for aSyncLoopTarget is not allowed.
StopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate,
already_AddRefed<nsIEventTarget> aSyncLoopTarget,
bool aResult);
// By default StopSyncLoopRunnables cannot be canceled since they could leave
// a sync loop spinning forever.
NS_DECL_NSICANCELABLERUNNABLE
protected:
virtual ~StopSyncLoopRunnable()
{ }
// Called on the worker thread to set an exception on the context if mResult
// is false. Override if you need an exception.
virtual void
MaybeSetException(JSContext* aCx)
{ }
private:
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
virtual bool
DispatchInternal() MOZ_OVERRIDE;
};
// This runnable is identical to StopSyncLoopRunnable except it is meant to be
// used on the main thread only.
class MainThreadStopSyncLoopRunnable : public StopSyncLoopRunnable
{
public:
// Passing null for aSyncLoopTarget is not allowed.
MainThreadStopSyncLoopRunnable(
WorkerPrivate* aWorkerPrivate,
already_AddRefed<nsIEventTarget> aSyncLoopTarget,
bool aResult)
: StopSyncLoopRunnable(aWorkerPrivate, aSyncLoopTarget, aResult)
{
AssertIsOnMainThread();
}
protected:
virtual ~MainThreadStopSyncLoopRunnable()
{ }
private:
virtual bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
AssertIsOnMainThread();
return true;
}
virtual void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) MOZ_OVERRIDE;
};
// This runnable is processed as soon as it is received by the worker,
// potentially running before previously queued runnables and perhaps even with
// other JS code executing on the stack. These runnables must not alter the
// state of the JS runtime and should only twiddle state values. The busy count
// is never modified.
class WorkerControlRunnable : public WorkerRunnable
{
friend class WorkerPrivate;
protected:
WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
TargetAndBusyBehavior aBehavior)
#ifdef DEBUG
;
#else
: WorkerRunnable(aWorkerPrivate, aBehavior)
{ }
#endif
virtual ~WorkerControlRunnable()
{ }
public:
NS_DECL_ISUPPORTS_INHERITED
private:
virtual bool
DispatchInternal() MOZ_OVERRIDE;
// Should only be called by WorkerPrivate::DoRunLoop.
using WorkerRunnable::Cancel;
};
// A convenience class for WorkerControlRunnables that originate on the main
// thread.
class MainThreadWorkerControlRunnable : public WorkerControlRunnable
{
protected:
MainThreadWorkerControlRunnable(WorkerPrivate* aWorkerPrivate)
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
{ }
virtual ~MainThreadWorkerControlRunnable()
{ }
virtual bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
AssertIsOnMainThread();
return true;
}
virtual void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult) MOZ_OVERRIDE;
};
END_WORKERS_NAMESPACE
#endif // mozilla_dom_workers_workerrunnable_h__

Просмотреть файл

@ -184,39 +184,50 @@ SuspendWorkersForWindow(nsPIDOMWindow* aWindow);
void
ResumeWorkersForWindow(nsPIDOMWindow* aWindow);
class WorkerTask {
class WorkerTask
{
protected:
WorkerTask()
{ }
virtual ~WorkerTask()
{ }
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerTask)
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerTask)
virtual ~WorkerTask() { }
virtual bool RunTask(JSContext* aCx) = 0;
virtual bool
RunTask(JSContext* aCx) = 0;
};
class WorkerCrossThreadDispatcher {
class WorkerCrossThreadDispatcher
{
friend class WorkerPrivate;
// Must be acquired *before* the WorkerPrivate's mutex, when they're both
// held.
Mutex mMutex;
WorkerPrivate* mWorkerPrivate;
private:
// Only created by WorkerPrivate.
WorkerCrossThreadDispatcher(WorkerPrivate* aWorkerPrivate);
// Only called by WorkerPrivate.
void
Forget()
{
MutexAutoLock lock(mMutex);
mWorkerPrivate = nullptr;
}
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerCrossThreadDispatcher)
WorkerCrossThreadDispatcher(WorkerPrivate* aPrivate) :
mMutex("WorkerCrossThreadDispatcher"), mPrivate(aPrivate) {}
void Forget()
{
mozilla::MutexAutoLock lock(mMutex);
mPrivate = nullptr;
}
/**
* Generically useful function for running a bit of C++ code on the worker
* thread.
*/
bool PostTask(WorkerTask* aTask);
protected:
friend class WorkerPrivate;
// Must be acquired *before* the WorkerPrivate's mutex, when they're both held.
mozilla::Mutex mMutex;
WorkerPrivate* mPrivate;
// Generically useful function for running a bit of C++ code on the worker
// thread.
bool
PostTask(WorkerTask* aTask);
};
WorkerCrossThreadDispatcher*

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -22,8 +22,8 @@ class Proxy;
class XMLHttpRequestUpload;
class WorkerPrivate;
class XMLHttpRequest : public nsXHREventTarget,
public WorkerFeature
class XMLHttpRequest MOZ_FINAL: public nsXHREventTarget,
public WorkerFeature
{
public:
struct StateData
@ -61,10 +61,6 @@ private:
bool mMozAnon;
bool mMozSystem;
protected:
XMLHttpRequest(WorkerPrivate* aWorkerPrivate);
virtual ~XMLHttpRequest();
public:
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
@ -272,6 +268,9 @@ public:
}
private:
XMLHttpRequest(WorkerPrivate* aWorkerPrivate);
~XMLHttpRequest();
enum ReleaseType { Default, XHRIsGoingAway, WorkerIsGoingAway };
void

Просмотреть файл

@ -9,6 +9,7 @@ TEST_DIRS += ['test']
# Public stuff.
EXPORTS.mozilla.dom += [
'WorkerPrivate.h',
'WorkerRunnable.h',
'WorkerScope.h',
]
@ -43,6 +44,7 @@ SOURCES += [
'SharedWorker.cpp',
'URL.cpp',
'WorkerPrivate.cpp',
'WorkerRunnable.cpp',
'WorkerScope.cpp',
'XMLHttpRequest.cpp',
'XMLHttpRequestUpload.cpp',
@ -58,6 +60,7 @@ LOCAL_INCLUDES += [
'/content/base/src',
'/content/events/src',
'/xpcom/build',
'/xpcom/threads',
]
include('/ipc/chromium/chromium-config.mozbuild')

30
gfx/2d/StackArray.h Normal file
Просмотреть файл

@ -0,0 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A handy class that will allocate data for size*T objects on the stack and
* otherwise allocate them on the heap. It is similar in purpose to nsAutoTArray */
template <class T, size_t size>
class StackArray
{
public:
StackArray(size_t count) {
if (count > size) {
mData = new T[count];
} else {
mData = mStackData;
}
}
~StackArray() {
if (mData != mStackData) {
delete[] mData;
}
}
T& operator[](size_t n) { return mData[n]; }
const T& operator[](size_t n) const { return mData[n]; }
T* data() { return mData; };
private:
T mStackData[size];
T* mData;
};

Просмотреть файл

@ -153,17 +153,18 @@ YCbCrImageDataSerializer::ComputeMinBufferSize(uint32_t aSize)
}
void
YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize,
YCbCrImageDataSerializer::InitializeBufferInfo(uint32_t aYOffset,
uint32_t aCbOffset,
uint32_t aCrOffset,
const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize,
StereoMode aStereoMode)
{
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
info->mYOffset = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
info->mCbOffset = info->mYOffset
+ MOZ_ALIGN_WORD(aYSize.width * aYSize.height);
info->mCrOffset = info->mCbOffset
+ MOZ_ALIGN_WORD(aCbCrSize.width * aCbCrSize.height);
uint32_t info_size = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
info->mYOffset = info_size + aYOffset;
info->mCbOffset = info_size + aCbOffset;
info->mCrOffset = info_size + aCrOffset;
info->mYWidth = aYSize.width;
info->mYHeight = aYSize.height;
info->mCbCrWidth = aCbCrSize.width;
@ -171,6 +172,17 @@ YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize,
info->mStereoMode = aStereoMode;
}
void
YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize,
StereoMode aStereoMode)
{
uint32_t yOffset = 0;
uint32_t cbOffset = yOffset + MOZ_ALIGN_WORD(aYSize.width * aYSize.height);
uint32_t crOffset = cbOffset + MOZ_ALIGN_WORD(aCbCrSize.width * aCbCrSize.height);
return InitializeBufferInfo(yOffset, cbOffset, crOffset, aYSize, aCbCrSize, aStereoMode);
}
void
YCbCrImageDataSerializer::InitializeBufferInfo(const gfxIntSize& aYSize,
const gfxIntSize& aCbCrSize,

Просмотреть файл

@ -114,6 +114,12 @@ public:
* The provided pointer should point to the beginning of the (chunk of)
* buffer on which we want to store the image.
*/
void InitializeBufferInfo(uint32_t aYOffset,
uint32_t aCbOffset,
uint32_t aCrOffset,
const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize,
StereoMode aStereoMode);
void InitializeBufferInfo(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize,
StereoMode aStereoMode);

Просмотреть файл

@ -1213,21 +1213,6 @@ const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort(
scrollOffset.y = scrollableRect.y;
}
// FIXME/bug 936500: Make sure the displayport contains the composition
// bounds. This is to work around a layout bug that means if a display item's
// corresponding displayport doesn't contain its frame's bounds, it may get
// optimised out and the layer won't get created.
if (displayPort.x + displayPort.width < compositionBounds.width) {
displayPort.x = -(displayPort.width - compositionBounds.width);
} else if (displayPort.x > 0) {
displayPort.x = 0;
}
if (displayPort.y + displayPort.height < compositionBounds.height) {
displayPort.y = -(displayPort.height - compositionBounds.height);
} else if (displayPort.y > 0) {
displayPort.y = 0;
}
CSSRect shiftedDisplayPort = displayPort + scrollOffset;
return scrollableRect.ClampRect(shiftedDisplayPort) - scrollOffset;
}

Просмотреть файл

@ -143,8 +143,21 @@ SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
{
mData = aData;
mSize = aData.mPicSize;
/* SetDataNoCopy is used to update YUV plane offsets without (re)allocating
* memory previously allocated with AllocateAndGetNewBuffer().
* serializer.GetData() returns the address of the memory previously allocated
* with AllocateAndGetNewBuffer(), that we subtract from the Y, Cb, Cr
* channels to compute 0-based offsets to pass to InitializeBufferInfo.
*/
YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer());
serializer.InitializeBufferInfo(aData.mYSize,
uint8_t *base = serializer.GetData();
uint32_t yOffset = aData.mYChannel - base;
uint32_t cbOffset = aData.mCbChannel - base;
uint32_t crOffset = aData.mCrChannel - base;
serializer.InitializeBufferInfo(yOffset,
cbOffset,
crOffset,
aData.mYSize,
aData.mCbCrSize,
aData.mStereoMode);
}

Просмотреть файл

@ -78,16 +78,13 @@ bool
EXIFParser::ParseTIFFHeader(uint32_t& aIFD0OffsetOut)
{
// Determine byte order.
if (MatchString("MM", 2))
if (MatchString("MM\0*", 4))
mByteOrder = ByteOrder::BigEndian;
else if (MatchString("II", 2))
else if (MatchString("II*\0", 4))
mByteOrder = ByteOrder::LittleEndian;
else
return false;
if (!MatchString("\0*", 2))
return false;
// Determine offset of the 0th IFD. (It shouldn't be greater than 64k, which
// is the maximum size of the entry APP1 segment.)
uint32_t ifd0Offset;

Просмотреть файл

@ -397,7 +397,7 @@ IntlInitialize(JSContext *cx, HandleObject obj, Handle<PropertyName*> initialize
HandleValue locales, HandleValue options)
{
RootedValue initializerValue(cx);
if (!cx->global()->getIntrinsicValue(cx, initializer, &initializerValue))
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), initializer, &initializerValue))
return false;
JS_ASSERT(initializerValue.isObject());
JS_ASSERT(initializerValue.toObject().is<JSFunction>());
@ -463,7 +463,7 @@ static bool
GetInternals(JSContext *cx, HandleObject obj, MutableHandleObject internals)
{
RootedValue getInternalsValue(cx);
if (!cx->global()->getIntrinsicValue(cx, cx->names().getInternals, &getInternalsValue))
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().getInternals, &getInternalsValue))
return false;
JS_ASSERT(getInternalsValue.isObject());
JS_ASSERT(getInternalsValue.toObject().is<JSFunction>());
@ -690,7 +690,7 @@ InitCollatorClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global
* passing to methods like Array.prototype.sort).
*/
RootedValue getter(cx);
if (!cx->global()->getIntrinsicValue(cx, cx->names().CollatorCompareGet, &getter))
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().CollatorCompareGet, &getter))
return nullptr;
RootedValue undefinedValue(cx, UndefinedValue());
if (!JSObject::defineProperty(cx, proto, cx->names().compare, undefinedValue,
@ -1178,7 +1178,7 @@ InitNumberFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> gl
* for passing to methods like Array.prototype.map).
*/
RootedValue getter(cx);
if (!cx->global()->getIntrinsicValue(cx, cx->names().NumberFormatFormatGet, &getter))
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().NumberFormatFormatGet, &getter))
return nullptr;
RootedValue undefinedValue(cx, UndefinedValue());
if (!JSObject::defineProperty(cx, proto, cx->names().format, undefinedValue,
@ -1635,7 +1635,7 @@ InitDateTimeFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*>
* (suitable for passing to methods like Array.prototype.map).
*/
RootedValue getter(cx);
if (!cx->global()->getIntrinsicValue(cx, cx->names().DateTimeFormatFormatGet, &getter))
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().DateTimeFormatFormatGet, &getter))
return nullptr;
RootedValue undefinedValue(cx, UndefinedValue());
if (!JSObject::defineProperty(cx, proto, cx->names().format, undefinedValue,

Просмотреть файл

@ -709,18 +709,18 @@ AllLocalsAliased(StaticBlockObject &obj)
#endif
static bool
ComputeAliasedSlots(ExclusiveContext *cx, BytecodeEmitter *bce, StaticBlockObject &blockObj)
ComputeAliasedSlots(ExclusiveContext *cx, BytecodeEmitter *bce, Handle<StaticBlockObject *> blockObj)
{
uint32_t depthPlusFixed = blockObj.stackDepth();
uint32_t depthPlusFixed = blockObj->stackDepth();
if (!AdjustBlockSlot(cx, bce, &depthPlusFixed))
return false;
for (unsigned i = 0; i < blockObj.slotCount(); i++) {
Definition *dn = blockObj.maybeDefinitionParseNode(i);
for (unsigned i = 0; i < blockObj->slotCount(); i++) {
Definition *dn = blockObj->maybeDefinitionParseNode(i);
/* Beware the empty destructuring dummy. */
if (!dn) {
blockObj.setAliased(i, bce->sc->allLocalsAliased());
blockObj->setAliased(i, bce->sc->allLocalsAliased());
continue;
}
@ -738,10 +738,10 @@ ComputeAliasedSlots(ExclusiveContext *cx, BytecodeEmitter *bce, StaticBlockObjec
}
#endif
blockObj.setAliased(i, bce->isAliasedName(dn));
blockObj->setAliased(i, bce->isAliasedName(dn));
}
JS_ASSERT_IF(bce->sc->allLocalsAliased(), AllLocalsAliased(blockObj));
JS_ASSERT_IF(bce->sc->allLocalsAliased(), AllLocalsAliased(*blockObj));
return true;
}
@ -809,18 +809,18 @@ EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, O
parent = stmt->blockScopeIndex;
}
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
Rooted<StaticBlockObject *> blockObj(cx, &objbox->object->as<StaticBlockObject>());
uint32_t scopeObjectIndex = bce->objectList.add(objbox);
int depth = bce->stackDepth - (blockObj.slotCount() + extraSlots);
int depth = bce->stackDepth - (blockObj->slotCount() + extraSlots);
JS_ASSERT(depth >= 0);
blockObj.setStackDepth(depth);
blockObj->setStackDepth(depth);
if (!ComputeAliasedSlots(cx, bce, blockObj))
return false;
if (blockObj.needsClone()) {
if (blockObj->needsClone()) {
if (!EmitInternedObjectOp(cx, scopeObjectIndex, JSOP_PUSHBLOCKSCOPE, bce))
return false;
}
@ -830,8 +830,8 @@ EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, O
return false;
PushStatementBCE(bce, stmt, STMT_BLOCK, bce->offset());
blockObj.initEnclosingStaticScope(EnclosingStaticScope(bce));
FinishPushBlockScope(bce, stmt, blockObj);
blockObj->initEnclosingStaticScope(EnclosingStaticScope(bce));
FinishPushBlockScope(bce, stmt, *blockObj);
JS_ASSERT(stmt->isBlockScope);
@ -2384,7 +2384,7 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* If there are hoisted let declarations, their stack slots go under the
* discriminant's value so push their slots now and enter the block later.
*/
StaticBlockObject *blockObj = nullptr;
Rooted<StaticBlockObject *> blockObj(cx, nullptr);
if (pn2->isKind(PNK_LEXICALSCOPE)) {
blockObj = &pn2->pn_objbox->object->as<StaticBlockObject>();
for (uint32_t i = 0; i < blockObj->slotCount(); ++i) {
@ -2804,7 +2804,13 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo
/* Initialize fun->script() so that the debugger has a valid fun->script(). */
RootedFunction fun(cx, bce->script->function());
JS_ASSERT(fun->isInterpreted());
fun->setScript(bce->script);
if (fun->isInterpretedLazy()) {
AutoLockForCompilation lock(cx);
fun->setUnlazifiedScript(bce->script);
} else {
fun->setScript(bce->script);
}
bce->tellDebuggerAboutCompiledScript(cx);

Просмотреть файл

@ -2853,17 +2853,18 @@ Parser<ParseHandler>::bindVarOrConst(BindData<ParseHandler> *data,
if (pc->sc->isFunctionBox()) {
FunctionBox *funbox = pc->sc->asFunctionBox();
funbox->setMightAliasLocals();
/*
* This definition isn't being added to the parse context's
* declarations, so make sure to indicate the need to deoptimize
* the script's arguments object. Mark the function as if it
* contained a debugger statement, which will deoptimize arguments
* as much as possible.
*/
if (name == cx->names().arguments)
funbox->setHasDebuggerStatement();
}
/*
* This definition isn't being added to the parse context's
* declarations, so make sure to indicate the need to deoptimize
* the script's arguments object. Mark the function as if it
* contained a debugger statement, which will deoptimize arguments
* as much as possible.
*/
if (name == cx->names().arguments)
pc->sc->setHasDebuggerStatement();
return true;
}

Просмотреть файл

@ -1129,23 +1129,17 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
PushMarkStack(gcmarker, JSID_TO_STRING(prop->id));
}
if (TaggedProto(type->proto).isObject())
PushMarkStack(gcmarker, type->proto);
if (type->proto().isObject())
PushMarkStack(gcmarker, type->proto().toObject());
if (type->singleton && !type->lazy())
PushMarkStack(gcmarker, type->singleton);
if (type->addendum) {
switch (type->addendum->kind) {
case types::TypeObjectAddendum::NewScript:
PushMarkStack(gcmarker, type->newScript()->fun);
PushMarkStack(gcmarker, type->newScript()->templateObject);
break;
case types::TypeObjectAddendum::TypedObject:
PushMarkStack(gcmarker, type->typedObject()->typeRepr->ownerObject());
break;
}
if (type->hasNewScript()) {
PushMarkStack(gcmarker, type->newScript()->fun);
PushMarkStack(gcmarker, type->newScript()->templateObject);
} else if (type->hasTypedObject()) {
PushMarkStack(gcmarker, type->typedObject()->typeRepr->ownerObject());
}
if (type->interpretedFunction)
@ -1162,23 +1156,17 @@ gc::MarkChildren(JSTracer *trc, types::TypeObject *type)
MarkId(trc, &prop->id, "type_prop");
}
if (TaggedProto(type->proto).isObject())
MarkObject(trc, &type->proto, "type_proto");
if (type->proto().isObject())
MarkObject(trc, &type->protoRaw(), "type_proto");
if (type->singleton && !type->lazy())
MarkObject(trc, &type->singleton, "type_singleton");
if (type->addendum) {
switch (type->addendum->kind) {
case types::TypeObjectAddendum::NewScript:
MarkObject(trc, &type->newScript()->fun, "type_new_function");
MarkObject(trc, &type->newScript()->templateObject, "type_new_template");
break;
case types::TypeObjectAddendum::TypedObject:
type->typedObject()->typeRepr->mark(trc);
break;
}
if (type->hasNewScript()) {
MarkObject(trc, &type->newScript()->fun, "type_new_function");
MarkObject(trc, &type->newScript()->templateObject, "type_new_template");
} else if (type->hasTypedObject()) {
type->typedObject()->typeRepr->mark(trc);
}
if (type->interpretedFunction)
@ -1441,7 +1429,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
PushMarkStack(this, shape);
/* Call the trace hook if necessary. */
const Class *clasp = type->clasp;
const Class *clasp = type->clasp();
if (clasp->trace) {
JS_ASSERT_IF(runtime->gcMode() == JSGC_MODE_INCREMENTAL &&
runtime->gcIncrementalEnabled,

Просмотреть файл

@ -47,7 +47,7 @@ MarkExactStackRoot(JSTracer *trc, Rooted<void*> *rooter, ThingRootKind kind)
if (IsNullTaggedPointer(*addr))
return;
if (kind == THING_ROOT_OBJECT && *addr == Proxy::LazyProto)
if (kind == THING_ROOT_OBJECT && *addr == TaggedProto::LazyProto)
return;
switch (kind) {

Просмотреть файл

@ -107,38 +107,6 @@ assertTypeFailInEval('function f(global, {imports}) { "use asm"; function g() {}
assertTypeFailInEval('function f(g = 2) { "use asm"; function g() {} return g }');
assertTypeFailInEval('function *f() { "use asm"; function g() {} return g }');
function assertLinkFailInEval(str)
{
if (!isAsmJSCompilationAvailable())
return;
var caught = false;
var oldOpts = options("werror");
assertEq(oldOpts.indexOf("werror"), -1);
try {
eval(str);
} catch (e) {
assertEq((''+e).indexOf(ASM_OK_STRING) == -1, false);
caught = true;
}
assertEq(caught, true);
options("werror");
var code = eval(str);
var caught = false;
var oldOpts = options("werror");
assertEq(oldOpts.indexOf("werror"), -1);
try {
code.apply(null, Array.slice(arguments, 1));
} catch (e) {
caught = true;
}
assertEq(caught, true);
options("werror");
}
assertLinkFailInEval('(function(global) { "use asm"; var im=global.Math.imul; function g() {} return g })');
assertThrowsInstanceOf(function() { new Function(USE_ASM + 'var)') }, SyntaxError);
assertThrowsInstanceOf(function() { new Function(USE_ASM + 'return)') }, SyntaxError);
assertThrowsInstanceOf(function() { new Function(USE_ASM + 'var z=-2w') }, SyntaxError);

Просмотреть файл

@ -0,0 +1,10 @@
function test1() {
eval("with (arguments) var arguments = 0;");
}
test1();
function test2() {
eval("eval('with (arguments) var arguments = 0;')");
}
test2();

Просмотреть файл

@ -186,10 +186,8 @@ BaselineCompiler::compile()
baselineScript->setMethod(code);
baselineScript->setTemplateScope(templateScope);
script->setBaselineScript(baselineScript);
IonSpew(IonSpew_BaselineScripts, "Created BaselineScript %p (raw %p) for %s:%d",
(void *) script->baselineScript(), (void *) code->raw(),
(void *) baselineScript, (void *) code->raw(),
script->filename(), script->lineno());
#ifdef JS_ION_PERF
@ -254,6 +252,8 @@ BaselineCompiler::compile()
if (script->compartment()->debugMode())
baselineScript->setDebugMode();
script->setBaselineScript(cx, baselineScript);
return Method_Compiled;
}

Просмотреть файл

@ -130,12 +130,16 @@ ICStubIterator::operator++()
}
void
ICStubIterator::unlink(Zone *zone)
ICStubIterator::unlink(JSContext *cx)
{
JS_ASSERT(currentStub_->next() != nullptr);
JS_ASSERT(currentStub_ != fallbackStub_);
JS_ASSERT(!unlinked_);
fallbackStub_->unlinkStub(zone, previousStub_, currentStub_);
{
AutoLockForCompilation lock(cx);
fallbackStub_->unlinkStub(cx->zone(), previousStub_, currentStub_);
}
// Mark the current iterator position as unlinked, so operator++ works properly.
unlinked_ = true;
@ -172,14 +176,14 @@ ICStub::trace(JSTracer *trc)
ICTypeMonitor_Fallback *lastMonStub = toMonitoredFallbackStub()->fallbackMonitorStub();
for (ICStubConstIterator iter = lastMonStub->firstMonitorStub(); !iter.atEnd(); iter++) {
JS_ASSERT_IF(iter->next() == nullptr, *iter == lastMonStub);
iter->markCode(trc, "baseline-monitor-stub-ioncode");
iter->trace(trc);
}
}
if (isUpdated()) {
for (ICStubConstIterator iter = toUpdatedStub()->firstUpdateStub(); !iter.atEnd(); iter++) {
JS_ASSERT_IF(iter->next() == nullptr, iter->isTypeUpdate_Fallback());
iter->markCode(trc, "baseline-update-stub-ioncode");
iter->trace(trc);
}
}
@ -485,7 +489,7 @@ ICFallbackStub::unlinkStubsWithKind(JSContext *cx, ICStub::Kind kind)
{
for (ICStubIterator iter = beginChain(); !iter.atEnd(); iter++) {
if (iter->kind() == kind)
iter.unlink(cx->zone());
iter.unlink(cx);
}
}
@ -1061,7 +1065,7 @@ DoProfilerFallback(JSContext *cx, BaselineFrame *frame, ICProfiler_Fallback *stu
ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
if (!optStub)
return false;
stub->addNewStub(optStub);
stub->addNewStub(cx, optStub);
return true;
}
@ -1146,8 +1150,10 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, HandleScript scrip
ICTypeMonitor_PrimitiveSet::Compiler compiler(cx, existingStub, type);
ICStub *stub = existingStub ? compiler.updateStub()
: compiler.getStub(compiler.getStubSpace(script));
if (!stub)
if (!stub) {
js_ReportOutOfMemory(cx);
return false;
}
IonSpew(IonSpew_BaselineIC, " %s TypeMonitor stub %p for primitive type %d",
existingStub ? "Modified existing" : "Created new", stub, type);
@ -1171,8 +1177,10 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, HandleScript scrip
ICTypeMonitor_SingleObject::Compiler compiler(cx, obj);
ICStub *stub = compiler.getStub(compiler.getStubSpace(script));
if (!stub)
if (!stub) {
js_ReportOutOfMemory(cx);
return false;
}
IonSpew(IonSpew_BaselineIC, " Added TypeMonitor stub %p for singleton %p",
stub, obj.get());
@ -1193,8 +1201,10 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, HandleScript scrip
ICTypeMonitor_TypeObject::Compiler compiler(cx, type);
ICStub *stub = compiler.getStub(compiler.getStubSpace(script));
if (!stub)
if (!stub) {
js_ReportOutOfMemory(cx);
return false;
}
IonSpew(IonSpew_BaselineIC, " Added TypeMonitor stub %p for TypeObject %p",
stub, type.get());
@ -1785,7 +1795,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
if (!int32Stub)
return false;
stub->addNewStub(int32Stub);
stub->addNewStub(cx, int32Stub);
return true;
}
@ -1803,7 +1813,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
if (!doubleStub)
return false;
stub->addNewStub(doubleStub);
stub->addNewStub(cx, doubleStub);
return true;
}
@ -1818,7 +1828,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
if (!doubleStub)
return false;
stub->addNewStub(doubleStub);
stub->addNewStub(cx, doubleStub);
return true;
}
@ -1829,7 +1839,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
if (!booleanStub)
return false;
stub->addNewStub(booleanStub);
stub->addNewStub(cx, booleanStub);
return true;
}
@ -1842,7 +1852,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
if (!optStub)
return false;
stub->addNewStub(optStub);
stub->addNewStub(cx, optStub);
return true;
}
@ -1854,7 +1864,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
if (!stringStub)
return false;
stub->addNewStub(stringStub);
stub->addNewStub(cx, stringStub);
return true;
}
@ -1866,7 +1876,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
if (!objectStub)
return false;
stub->addNewStub(objectStub);
stub->addNewStub(cx, objectStub);
return true;
}
@ -1884,7 +1894,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub,
if (!objectStub)
return false;
stub->addNewStub(objectStub);
stub->addNewStub(cx, objectStub);
return true;
}
}
@ -2090,7 +2100,7 @@ ICCompare_ObjectWithUndefined::Compiler::generateStubCode(MacroAssembler &masm)
Label emulatesUndefined;
Register obj = masm.extractObject(objectOperand, ExtractTemp0);
masm.loadPtr(Address(obj, JSObject::offsetOfType()), obj);
masm.loadPtr(Address(obj, offsetof(types::TypeObject, clasp)), obj);
masm.loadPtr(Address(obj, types::TypeObject::offsetOfClasp()), obj);
masm.branchTest32(Assembler::NonZero,
Address(obj, Class::offsetOfFlags()),
Imm32(JSCLASS_EMULATES_UNDEFINED),
@ -2196,7 +2206,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H
if (!int32Stub)
return false;
stub->addNewStub(int32Stub);
stub->addNewStub(cx, int32Stub);
return true;
}
@ -2207,7 +2217,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H
if (!doubleStub)
return false;
stub->addNewStub(doubleStub);
stub->addNewStub(cx, doubleStub);
return true;
}
@ -2218,7 +2228,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H
if (!stringStub)
return false;
stub->addNewStub(stringStub);
stub->addNewStub(cx, stringStub);
return true;
}
@ -2228,7 +2238,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H
if (!nilStub)
return false;
stub->addNewStub(nilStub);
stub->addNewStub(cx, nilStub);
return true;
}
@ -2239,7 +2249,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H
if (!objStub)
return false;
stub->addNewStub(objStub);
stub->addNewStub(cx, objStub);
return true;
}
@ -2531,11 +2541,11 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
}
if (ret.isDouble())
stub->setSawDoubleResult();
stub->setSawDoubleResult(cx);
// Check to see if a new stub should be generated.
if (stub->numOptimizedStubs() >= ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
stub->noteUnoptimizableOperands();
stub->noteUnoptimizableOperands(cx);
return true;
}
@ -2548,7 +2558,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script));
if (!strcatStub)
return false;
stub->addNewStub(strcatStub);
stub->addNewStub(cx, strcatStub);
return true;
}
@ -2561,7 +2571,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script));
if (!strcatStub)
return false;
stub->addNewStub(strcatStub);
stub->addNewStub(cx, strcatStub);
return true;
}
}
@ -2577,13 +2587,13 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
ICStub *arithStub = compiler.getStub(compiler.getStubSpace(script));
if (!arithStub)
return false;
stub->addNewStub(arithStub);
stub->addNewStub(cx, arithStub);
return true;
}
// Handle only int32 or double.
if (!lhs.isNumber() || !rhs.isNumber()) {
stub->noteUnoptimizableOperands();
stub->noteUnoptimizableOperands(cx);
return true;
}
@ -2607,7 +2617,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
if (!doubleStub)
return false;
stub->addNewStub(doubleStub);
stub->addNewStub(cx, doubleStub);
return true;
}
default:
@ -2625,7 +2635,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
ICStub *int32Stub = compilerInt32.getStub(compilerInt32.getStubSpace(script));
if (!int32Stub)
return false;
stub->addNewStub(int32Stub);
stub->addNewStub(cx, int32Stub);
return true;
}
@ -2644,7 +2654,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
if (!optStub)
return false;
stub->addNewStub(optStub);
stub->addNewStub(cx, optStub);
return true;
}
default:
@ -2652,7 +2662,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac
}
}
stub->noteUnoptimizableOperands();
stub->noteUnoptimizableOperands(cx);
return true;
}
#if defined(_MSC_VER)
@ -3047,7 +3057,7 @@ DoUnaryArithFallback(JSContext *cx, BaselineFrame *frame, ICUnaryArith_Fallback
ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
if (!int32Stub)
return false;
stub->addNewStub(int32Stub);
stub->addNewStub(cx, int32Stub);
return true;
}
@ -3061,7 +3071,7 @@ DoUnaryArithFallback(JSContext *cx, BaselineFrame *frame, ICUnaryArith_Fallback
ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
if (!doubleStub)
return false;
stub->addNewStub(doubleStub);
stub->addNewStub(cx, doubleStub);
return true;
}
@ -3629,7 +3639,7 @@ RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, Handle
// If the holder matches, but the holder's lastProperty doesn't match, then
// this stub is invalid anyway. Unlink it.
if (holder->lastProperty() != protoStub->holderShape()) {
iter.unlink(cx->zone());
iter.unlink(cx);
continue;
}
} else {
@ -3645,7 +3655,7 @@ RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, Handle
// If the holder matches, but the holder's lastProperty doesn't match, then
// this stub is invalid anyway. Unlink it.
if (holder->lastProperty() != protoStub->holderShape()) {
iter.unlink(cx->zone());
iter.unlink(cx);
continue;
}
}
@ -3654,7 +3664,7 @@ RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, Handle
// If the new stub needs atomization, and the old stub doesn't atomize, then
// remove the old stub.
if (needsAtomize && !getElemNativeStub->needsAtomize()) {
iter.unlink(cx->zone());
iter.unlink(cx);
continue;
}
@ -3745,7 +3755,7 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -3797,7 +3807,7 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -3831,7 +3841,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
if (!stringStub)
return false;
stub->addNewStub(stringStub);
stub->addNewStub(cx, stringStub);
return true;
}
@ -3849,7 +3859,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
if (!argsStub)
return false;
stub->addNewStub(argsStub);
stub->addNewStub(cx, argsStub);
return true;
}
@ -3871,7 +3881,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
if (!argsStub)
return false;
stub->addNewStub(argsStub);
stub->addNewStub(cx, argsStub);
return true;
}
}
@ -3886,7 +3896,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
if (!denseStub)
return false;
stub->addNewStub(denseStub);
stub->addNewStub(cx, denseStub);
return true;
}
@ -3920,7 +3930,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
if (!typedArrayStub)
return false;
stub->addNewStub(typedArrayStub);
stub->addNewStub(cx, typedArrayStub);
return true;
}
@ -3928,13 +3938,13 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl
// be cached by either Baseline or Ion. Indicate this in the cache so that
// Ion does not generate a cache for this op.
if (!obj->isNative() && !obj->is<TypedArrayObject>())
stub->noteNonNativeAccess();
stub->noteNonNativeAccess(cx);
// GetElem operations which could access negative indexes generally can't
// be optimized without the potential for bailouts, as we can't statically
// determine that an object has no properties on such indexes.
if (rhs.isNumber() && rhs.toNumber() < 0)
stub->noteNegativeIndex();
stub->noteNegativeIndex(cx);
return true;
}
@ -4844,7 +4854,7 @@ RemoveExistingTypedArraySetElemStub(JSContext *cx, ICSetElem_Fallback *stub, Han
// TypedArraySetElem stubs are only removed using this procedure if
// being replaced with one that expects out of bounds index.
JS_ASSERT(!iter->toSetElem_TypedArray()->expectOutOfBounds());
iter.unlink(cx->zone());
iter.unlink(cx);
return true;
}
return false;
@ -5001,7 +5011,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs))
return false;
stub->addNewStub(denseStub);
stub->addNewStub(cx, denseStub);
} else if (!addingCase &&
!DenseSetElemStubExists(cx, ICStub::SetElem_Dense, stub, obj))
{
@ -5015,7 +5025,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs))
return false;
stub->addNewStub(denseStub);
stub->addNewStub(cx, denseStub);
}
}
@ -5048,7 +5058,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
if (!typedArrayStub)
return false;
stub->addNewStub(typedArrayStub);
stub->addNewStub(cx, typedArrayStub);
return true;
}
}
@ -5098,13 +5108,13 @@ ICSetElem_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
}
void
BaselineScript::noteArrayWriteHole(uint32_t pcOffset)
BaselineScript::noteArrayWriteHole(JSContext *cx, uint32_t pcOffset)
{
ICEntry &entry = icEntryFromPCOffset(pcOffset);
ICFallbackStub *stub = entry.fallbackStub();
if (stub->isSetElem_Fallback())
stub->toSetElem_Fallback()->noteArrayWriteHole();
stub->toSetElem_Fallback()->noteArrayWriteHole(cx);
}
//
@ -5626,7 +5636,7 @@ TryAttachGlobalNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -5716,7 +5726,7 @@ TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *s
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -5923,7 +5933,7 @@ DoGetIntrinsicFallback(JSContext *cx, BaselineFrame *frame, ICGetIntrinsic_Fallb
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -5971,7 +5981,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
return false;
*attached = true;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -5983,7 +5993,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
return false;
*attached = true;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -6000,7 +6010,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
return false;
*attached = true;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
if (obj->is<TypedArrayObject>()) {
@ -6012,7 +6022,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
return false;
*attached = true;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -6028,7 +6038,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
return false;
*attached = true;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -6111,7 +6121,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
*attached = true;
return true;
}
@ -6142,7 +6152,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
*attached = true;
return true;
}
@ -6189,7 +6199,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
}
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
*attached = true;
return true;
}
@ -6209,7 +6219,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
*attached = true;
return true;
}
@ -6263,7 +6273,7 @@ TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
*attached = true;
return true;
}
@ -6349,7 +6359,7 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub,
}
JS_ASSERT(!attached);
stub->noteUnoptimizableAccess();
stub->noteUnoptimizableAccess(cx);
return true;
}
@ -7094,13 +7104,13 @@ ICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler &masm)
}
void
BaselineScript::noteAccessedGetter(uint32_t pcOffset)
BaselineScript::noteAccessedGetter(JSContext *cx, uint32_t pcOffset)
{
ICEntry &entry = icEntryFromPCOffset(pcOffset);
ICFallbackStub *stub = entry.fallbackStub();
if (stub->isGetProp_Fallback())
stub->toGetProp_Fallback()->noteAccessedGetter();
stub->toGetProp_Fallback()->noteAccessedGetter(cx);
}
//
@ -7141,7 +7151,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
*attached = true;
return true;
}
@ -7159,7 +7169,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
*attached = true;
return true;
}
@ -7181,7 +7191,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
*attached = true;
return true;
}
@ -7200,7 +7210,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
*attached = true;
return true;
}
@ -7271,7 +7281,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub,
return true;
JS_ASSERT(!attached);
stub->noteUnoptimizableAccess();
stub->noteUnoptimizableAccess(cx);
return true;
}
@ -7775,7 +7785,7 @@ TryAttachFunApplyStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script,
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -7792,7 +7802,7 @@ TryAttachFunApplyStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script,
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
}
@ -7933,7 +7943,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
stub->unlinkStubsWithKind(cx, ICStub::Call_Scripted);
// Add new generalized stub.
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -7962,7 +7972,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -7999,7 +8009,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
return true;
}
@ -9123,7 +9133,7 @@ DoIteratorMoreFallback(JSContext *cx, BaselineFrame *frame, ICIteratorMore_Fallb
ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
}
return true;
@ -9197,7 +9207,7 @@ DoIteratorNextFallback(JSContext *cx, BaselineFrame *frame, ICIteratorNext_Fallb
return false;
if (!res.isString() && !stub->hasNonStringResult())
stub->setHasNonStringResult();
stub->setHasNonStringResult(cx);
if (iteratorObject->is<PropertyIteratorObject>() &&
!stub->hasStub(ICStub::IteratorNext_Native))
@ -9206,7 +9216,7 @@ DoIteratorNextFallback(JSContext *cx, BaselineFrame *frame, ICIteratorNext_Fallb
ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
if (!newStub)
return false;
stub->addNewStub(newStub);
stub->addNewStub(cx, newStub);
}
return true;
@ -9370,7 +9380,7 @@ DoTypeOfFallback(JSContext *cx, BaselineFrame *frame, ICTypeOf_Fallback *stub, H
ICStub *typeOfStub = compiler.getStub(compiler.getStubSpace(frame->script()));
if (!typeOfStub)
return false;
stub->addNewStub(typeOfStub);
stub->addNewStub(cx, typeOfStub);
}
return true;
@ -9457,7 +9467,7 @@ DoRetSubFallback(JSContext *cx, BaselineFrame *frame, ICRetSub_Fallback *stub,
if (!optStub)
return false;
stub->addNewStub(optStub);
stub->addNewStub(cx, optStub);
return true;
}

Просмотреть файл

@ -516,7 +516,7 @@ class ICStubIterator
return currentStub_ == (ICStub *) fallbackStub_;
}
void unlink(Zone *zone);
void unlink(JSContext *cx);
};
//
@ -687,6 +687,8 @@ class ICStub
}
inline void setNext(ICStub *stub) {
// Note: next_ only needs to be changed under the compilation lock for
// non-type-monitor/update ICs.
next_ = stub;
}
@ -833,7 +835,8 @@ class ICFallbackStub : public ICStub
}
// Add a new stub to the IC chain terminated by this fallback stub.
void addNewStub(ICStub *stub) {
void addNewStub(JSContext *cx, ICStub *stub) {
AutoLockForCompilation lock(cx);
JS_ASSERT(*lastStubPtrAddr_ == this);
JS_ASSERT(stub->next() == nullptr);
stub->setNext(this);
@ -2439,13 +2442,15 @@ class ICBinaryArith_Fallback : public ICFallbackStub
bool sawDoubleResult() const {
return extra_ & SAW_DOUBLE_RESULT_BIT;
}
void setSawDoubleResult() {
void setSawDoubleResult(JSContext *cx) {
AutoLockForCompilation lock(cx);
extra_ |= SAW_DOUBLE_RESULT_BIT;
}
bool hadUnoptimizableOperands() const {
return extra_ & UNOPTIMIZABLE_OPERANDS_BIT;
}
void noteUnoptimizableOperands() {
void noteUnoptimizableOperands(JSContext *cx) {
AutoLockForCompilation lock(cx);
extra_ |= UNOPTIMIZABLE_OPERANDS_BIT;
}
@ -2846,14 +2851,16 @@ class ICGetElem_Fallback : public ICMonitoredFallbackStub
return space->allocate<ICGetElem_Fallback>(code);
}
void noteNonNativeAccess() {
void noteNonNativeAccess(JSContext *cx) {
AutoLockForCompilation lock(cx);
extra_ |= EXTRA_NON_NATIVE;
}
bool hasNonNativeAccess() const {
return extra_ & EXTRA_NON_NATIVE;
}
void noteNegativeIndex() {
void noteNegativeIndex(JSContext *cx) {
AutoLockForCompilation lock(cx);
extra_ |= EXTRA_NEGATIVE_INDEX;
}
bool hasNegativeIndex() const {
@ -3441,7 +3448,8 @@ class ICSetElem_Fallback : public ICFallbackStub
return space->allocate<ICSetElem_Fallback>(code);
}
void noteArrayWriteHole() {
void noteArrayWriteHole(JSContext *cx) {
AutoLockForCompilation lock(cx);
extra_ = 1;
}
bool hasArrayWriteHole() const {
@ -4016,14 +4024,16 @@ class ICGetProp_Fallback : public ICMonitoredFallbackStub
static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
static const size_t ACCESSED_GETTER_BIT = 1;
void noteUnoptimizableAccess() {
void noteUnoptimizableAccess(JSContext *cx) {
AutoLockForCompilation lock(cx);
extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
}
bool hadUnoptimizableAccess() const {
return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
}
void noteAccessedGetter() {
void noteAccessedGetter(JSContext *cx) {
AutoLockForCompilation lock(cx);
extra_ |= (1u << ACCESSED_GETTER_BIT);
}
bool hasAccessedGetter() const {
@ -4830,7 +4840,8 @@ class ICSetProp_Fallback : public ICFallbackStub
}
static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
void noteUnoptimizableAccess() {
void noteUnoptimizableAccess(JSContext *cx) {
AutoLockForCompilation lock(cx);
extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
}
bool hadUnoptimizableAccess() const {
@ -5721,7 +5732,8 @@ class ICIteratorNext_Fallback : public ICFallbackStub
return space->allocate<ICIteratorNext_Fallback>(code);
}
void setHasNonStringResult() {
void setHasNonStringResult(JSContext *cx) {
AutoLockForCompilation lock(cx);
JS_ASSERT(extra_ == 0);
extra_ = 1;
}

Просмотреть файл

@ -18,6 +18,8 @@ using mozilla::DebugOnly;
bool
SetElemICInspector::sawOOBDenseWrite() const
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!icEntry_)
return false;
@ -38,6 +40,8 @@ SetElemICInspector::sawOOBDenseWrite() const
bool
SetElemICInspector::sawOOBTypedArrayWrite() const
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!icEntry_)
return false;
@ -54,6 +58,8 @@ SetElemICInspector::sawOOBTypedArrayWrite() const
bool
SetElemICInspector::sawDenseWrite() const
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!icEntry_)
return false;
@ -68,6 +74,8 @@ SetElemICInspector::sawDenseWrite() const
bool
SetElemICInspector::sawTypedArrayWrite() const
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!icEntry_)
return false;
@ -82,6 +90,8 @@ SetElemICInspector::sawTypedArrayWrite() const
bool
BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
// Return a list of shapes seen by the baseline IC for the current op.
// An empty list indicates no shapes are known, or there was an uncacheable
// access.
@ -139,6 +149,8 @@ BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
ICStub *
BaselineInspector::monomorphicStub(jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!hasBaselineScript())
return nullptr;
@ -156,6 +168,8 @@ BaselineInspector::monomorphicStub(jsbytecode *pc)
bool
BaselineInspector::dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **psecond)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!hasBaselineScript())
return false;
@ -176,6 +190,8 @@ BaselineInspector::dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **pseco
MIRType
BaselineInspector::expectedResultType(jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
// Look at the IC entries for this op to guess what type it will produce,
// returning MIRType_None otherwise.
@ -222,6 +238,8 @@ CanUseInt32Compare(ICStub::Kind kind)
MCompare::CompareType
BaselineInspector::expectedCompareType(jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
ICStub *first = monomorphicStub(pc), *second = nullptr;
if (!first && !dimorphicStub(pc, &first, &second))
return MCompare::Compare_Unknown;
@ -304,6 +322,8 @@ TryToSpecializeBinaryArithOp(ICStub **stubs,
MIRType
BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
MIRType result;
ICStub *stubs[2];
@ -332,6 +352,8 @@ BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc)
bool
BaselineInspector::hasSeenNonNativeGetElement(jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!hasBaselineScript())
return false;
@ -346,6 +368,8 @@ BaselineInspector::hasSeenNonNativeGetElement(jsbytecode *pc)
bool
BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!hasBaselineScript())
return false;
@ -360,6 +384,8 @@ BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode *pc)
bool
BaselineInspector::hasSeenAccessedGetter(jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!hasBaselineScript())
return false;
@ -374,6 +400,8 @@ BaselineInspector::hasSeenAccessedGetter(jsbytecode *pc)
bool
BaselineInspector::hasSeenNonStringIterNext(jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
JS_ASSERT(JSOp(*pc) == JSOP_ITERNEXT);
if (!hasBaselineScript())
@ -388,6 +416,8 @@ BaselineInspector::hasSeenNonStringIterNext(jsbytecode *pc)
bool
BaselineInspector::hasSeenDoubleResult(jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!hasBaselineScript())
return false;
@ -407,6 +437,8 @@ BaselineInspector::hasSeenDoubleResult(jsbytecode *pc)
JSObject *
BaselineInspector::getTemplateObject(jsbytecode *pc)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!hasBaselineScript())
return nullptr;
@ -434,6 +466,8 @@ BaselineInspector::getTemplateObject(jsbytecode *pc)
JSObject *
BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
if (!hasBaselineScript())
return nullptr;
@ -467,6 +501,8 @@ BaselineInspector::templateCallObject()
JSObject *
BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
const ICEntry &entry = icEntryFromPC(pc);
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
if (stub->isGetProp_CallScripted() || stub->isGetProp_CallNative()) {
@ -482,6 +518,8 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
JSObject *
BaselineInspector::commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
const ICEntry &entry = icEntryFromPC(pc);
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {

Просмотреть файл

@ -237,7 +237,7 @@ jit::BaselineCompile(JSContext *cx, HandleScript script)
JS_ASSERT_IF(status != Method_Compiled, !script->hasBaselineScript());
if (status == Method_CantCompile)
script->setBaselineScript(BASELINE_DISABLED_SCRIPT);
script->setBaselineScript(cx, BASELINE_DISABLED_SCRIPT);
return status;
}
@ -650,7 +650,7 @@ BaselineScript::copyPCMappingIndexEntries(const PCMappingIndexEntry *entries)
uint8_t *
BaselineScript::nativeCodeForPC(JSScript *script, jsbytecode *pc, PCMappingSlotInfo *slotInfo)
{
JS_ASSERT(script->baselineScript() == this);
JS_ASSERT_IF(script->hasBaselineScript(), script->baselineScript() == this);
uint32_t pcOffset = script->pcToOffset(pc);
@ -892,7 +892,7 @@ jit::FinishDiscardBaselineScript(FreeOp *fop, JSScript *script)
}
BaselineScript *baseline = script->baselineScript();
script->setBaselineScript(nullptr);
script->setBaselineScript(nullptr, nullptr);
BaselineScript::Destroy(fop, baseline);
}

Просмотреть файл

@ -289,8 +289,8 @@ struct BaselineScript
void toggleSPS(bool enable);
void noteAccessedGetter(uint32_t pcOffset);
void noteArrayWriteHole(uint32_t pcOffset);
void noteAccessedGetter(JSContext *cx, uint32_t pcOffset);
void noteArrayWriteHole(JSContext *cx, uint32_t pcOffset);
static size_t offsetOfFlags() {
return offsetof(BaselineScript, flags_);

Просмотреть файл

@ -36,8 +36,9 @@ bool
BitSet::empty() const
{
JS_ASSERT(bits_);
for (unsigned int i = 0; i < numWords(); i++) {
if (bits_[i])
const uint32_t *bits = bits_;
for (unsigned int i = 0, e = numWords(); i < e; i++) {
if (bits[i])
return false;
}
return true;
@ -50,8 +51,10 @@ BitSet::insertAll(const BitSet *other)
JS_ASSERT(other->numBits_ == numBits_);
JS_ASSERT(other->bits_);
for (unsigned int i = 0; i < numWords(); i++)
bits_[i] |= other->bits_[i];
uint32_t *bits = bits_;
const uint32_t *otherBits = other->bits_;
for (unsigned int i = 0, e = numWords(); i < e; i++)
bits[i] |= otherBits[i];
}
void
@ -61,8 +64,10 @@ BitSet::removeAll(const BitSet *other)
JS_ASSERT(other->numBits_ == numBits_);
JS_ASSERT(other->bits_);
for (unsigned int i = 0; i < numWords(); i++)
bits_[i] &= ~other->bits_[i];
uint32_t *bits = bits_;
const uint32_t *otherBits = other->bits_;
for (unsigned int i = 0, e = numWords(); i < e; i++)
bits[i] &= ~otherBits[i];
}
void
@ -72,8 +77,10 @@ BitSet::intersect(const BitSet *other)
JS_ASSERT(other->numBits_ == numBits_);
JS_ASSERT(other->bits_);
for (unsigned int i = 0; i < numWords(); i++)
bits_[i] &= other->bits_[i];
uint32_t *bits = bits_;
const uint32_t *otherBits = other->bits_;
for (unsigned int i = 0, e = numWords(); i < e; i++)
bits[i] &= otherBits[i];
}
// returns true if the intersection caused the contents of the set to change.
@ -86,11 +93,13 @@ BitSet::fixedPointIntersect(const BitSet *other)
bool changed = false;
for (unsigned int i = 0; i < numWords(); i++) {
uint32_t old = bits_[i];
bits_[i] &= other->bits_[i];
uint32_t *bits = bits_;
const uint32_t *otherBits = other->bits_;
for (unsigned int i = 0, e = numWords(); i < e; i++) {
uint32_t old = bits[i];
bits[i] &= otherBits[i];
if (!changed && old != bits_[i])
if (!changed && old != bits[i])
changed = true;
}
return changed;
@ -100,14 +109,16 @@ void
BitSet::complement()
{
JS_ASSERT(bits_);
for (unsigned int i = 0; i < numWords(); i++)
bits_[i] = ~bits_[i];
uint32_t *bits = bits_;
for (unsigned int i = 0, e = numWords(); i < e; i++)
bits[i] = ~bits[i];
}
void
BitSet::clear()
{
JS_ASSERT(bits_);
for (unsigned int i = 0; i < numWords(); i++)
bits_[i] = 0;
uint32_t *bits = bits_;
for (unsigned int i = 0, e = numWords(); i < e; i++)
bits[i] = 0;
}

Просмотреть файл

@ -29,11 +29,11 @@ class BitSet : private TempObject
private:
BitSet(unsigned int numBits) :
numBits_(numBits),
bits_(nullptr) {}
bits_(nullptr),
numBits_(numBits) {}
unsigned int numBits_;
uint32_t *bits_;
const unsigned int numBits_;
static inline uint32_t bitForValue(unsigned int value) {
return 1l << uint32_t(value % BitsPerWord);
@ -120,6 +120,29 @@ class BitSet::Iterator
unsigned word_;
uint32_t value_;
void skipEmpty() {
// Skip words containing only zeros.
unsigned numWords = set_.numWords();
const uint32_t *bits = set_.bits_;
while (value_ == 0) {
word_++;
if (word_ == numWords)
return;
JS_STATIC_ASSERT(sizeof(value_) * 8 == BitSet::BitsPerWord);
index_ = word_ * sizeof(value_) * 8;
value_ = bits[word_];
}
// Be careful: the result of CountTrailingZeroes32 is undefined if the
// input is 0.
int numZeros = mozilla::CountTrailingZeroes32(value_);
index_ += numZeros;
value_ >>= numZeros;
JS_ASSERT_IF(index_ < set_.numBits_, set_.contains(index_));
}
public:
Iterator(BitSet &set) :
set_(set),
@ -127,8 +150,7 @@ class BitSet::Iterator
word_(0),
value_(set.bits_[0])
{
if (!set_.contains(index_))
(*this)++;
skipEmpty();
}
inline bool more() const {
@ -145,23 +167,7 @@ class BitSet::Iterator
index_++;
value_ >>= 1;
// Skip words containing only zeros.
while (value_ == 0) {
word_++;
if (!more())
return *this;
index_ = word_ * sizeof(value_) * 8;
value_ = set_.bits_[word_];
}
// Be careful: the result of CountTrailingZeroes32 is undefined if the
// input is 0.
int numZeros = mozilla::CountTrailingZeroes32(value_);
index_ += numZeros;
value_ >>= numZeros;
JS_ASSERT_IF(index_ < set_.numBits_, set_.contains(index_));
skipEmpty();
return *this;
}

Просмотреть файл

@ -3389,14 +3389,14 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasLazyType() ? nullptr : templateObj->type()),
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
ToRegister(lir->slots())),
StoreRegisterTo(obj));
} else {
ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasLazyType() ? nullptr : templateObj->type()),
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
ImmPtr(nullptr)),
StoreRegisterTo(obj));
}
@ -7409,8 +7409,7 @@ CodeGenerator::emitInstanceOf(LInstruction *ins, JSObject *prototypeObject)
// out of the loop on Proxy::LazyProto.
// Load the lhs's prototype.
masm.loadPtr(Address(objReg, JSObject::offsetOfType()), output);
masm.loadPtr(Address(output, offsetof(types::TypeObject, proto)), output);
masm.loadObjProto(objReg, output);
Label testLazy;
{
@ -7424,14 +7423,13 @@ CodeGenerator::emitInstanceOf(LInstruction *ins, JSObject *prototypeObject)
masm.jump(&done);
masm.bind(&notPrototypeObject);
JS_ASSERT(uintptr_t(Proxy::LazyProto) == 1);
JS_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
// Test for nullptr or Proxy::LazyProto
masm.branchPtr(Assembler::BelowOrEqual, output, ImmWord(1), &testLazy);
// Load the current object's prototype.
masm.loadPtr(Address(output, JSObject::offsetOfType()), output);
masm.loadPtr(Address(output, offsetof(types::TypeObject, proto)), output);
masm.loadObjProto(output, output);
masm.jump(&loopPrototypeChain);
}

Просмотреть файл

@ -45,9 +45,9 @@ class CompileInfo
{
public:
CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing,
ExecutionMode executionMode)
ExecutionMode executionMode, bool scriptNeedsArgsObj)
: script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing),
executionMode_(executionMode)
executionMode_(executionMode), scriptNeedsArgsObj_(scriptNeedsArgsObj)
{
JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
@ -68,7 +68,7 @@ class CompileInfo
CompileInfo(unsigned nlocals, ExecutionMode executionMode)
: script_(nullptr), fun_(nullptr), osrPc_(nullptr), constructing_(false),
executionMode_(executionMode)
executionMode_(executionMode), scriptNeedsArgsObj_(false)
{
nimplicit_ = 0;
nargs_ = 0;
@ -250,10 +250,10 @@ class CompileInfo
return script()->argumentsAliasesFormals();
}
bool needsArgsObj() const {
return script()->needsArgsObj();
return scriptNeedsArgsObj_;
}
bool argsObjAliasesFormals() const {
return script()->argsObjAliasesFormals();
return scriptNeedsArgsObj_ && !script()->strict();
}
ExecutionMode executionMode() const {
@ -275,6 +275,11 @@ class CompileInfo
jsbytecode *osrPc_;
bool constructing_;
ExecutionMode executionMode_;
// Whether a script needs an arguments object is unstable over compilation
// since the arguments optimization could be marked as failed on the main
// thread, so cache a value here and use it throughout for consistency.
bool scriptNeedsArgsObj_;
};
} // namespace jit

Просмотреть файл

@ -125,11 +125,13 @@ CompileRuntime::positiveInfinityValue()
return runtime()->positiveInfinityValue;
}
#ifdef DEBUG
bool
CompileRuntime::isInsideNursery(gc::Cell *cell)
{
return UninlinedIsInsideNursery(runtime(), cell);
}
#endif
const DOMCallbacks *
CompileRuntime::DOMcallbacks()
@ -228,3 +230,10 @@ CompileCompartment::hasObjectMetadataCallback()
{
return compartment()->hasObjectMetadataCallback();
}
AutoLockForCompilation::AutoLockForCompilation(CompileCompartment *compartment
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
init(compartment->compartment()->runtimeFromAnyThread());
}

Просмотреть файл

@ -66,7 +66,9 @@ class CompileRuntime
const Value &NaNValue();
const Value &positiveInfinityValue();
#ifdef DEBUG
bool isInsideNursery(gc::Cell *cell);
#endif
// DOM callbacks must be threadsafe (and will hopefully be removed soon).
const DOMCallbacks *DOMcallbacks();
@ -96,6 +98,8 @@ class CompileCompartment
{
JSCompartment *compartment();
friend class js::AutoLockForCompilation;
public:
static CompileCompartment *get(JSCompartment *comp);

Просмотреть файл

@ -19,8 +19,8 @@ namespace jit {
template <typename T>
class FixedList
{
size_t length_;
T *list_;
size_t length_;
private:
FixedList(const FixedList&); // no copy definition.

Просмотреть файл

@ -49,6 +49,8 @@
using namespace js;
using namespace js::jit;
using mozilla::Maybe;
// Global variables.
IonOptions jit::js_IonOptions;
@ -516,6 +518,8 @@ JitCompartment::ensureIonStubsExist(JSContext *cx)
void
jit::FinishOffThreadBuilder(IonBuilder *builder)
{
builder->script()->runtimeFromMainThread()->removeCompilationThread();
ExecutionMode executionMode = builder->info().executionMode();
// Clear the recompiling flag if it would have failed.
@ -1563,6 +1567,9 @@ AttachFinishedCompilations(JSContext *cx)
// operation callback and can't propagate failures.
cx->clearPendingException();
}
} else {
if (builder->abortReason() == AbortReason_Disable)
SetIonScript(builder->script(), builder->info().executionMode(), ION_DISABLED_SCRIPT);
}
FinishOffThreadBuilder(builder);
@ -1663,11 +1670,13 @@ IonCompile(JSContext *cx, JSScript *script,
return AbortReason_Alloc;
CompileInfo *info = alloc->new_<CompileInfo>(script, script->function(), osrPc, constructing,
executionMode);
executionMode, script->needsArgsObj());
if (!info)
return AbortReason_Alloc;
BaselineInspector inspector(script);
BaselineInspector *inspector = alloc->new_<BaselineInspector>(script);
if (!inspector)
return AbortReason_Alloc;
BaselineFrameInspector *baselineFrameInspector = nullptr;
if (baselineFrame) {
@ -1686,7 +1695,7 @@ IonCompile(JSContext *cx, JSScript *script,
IonBuilder *builder = alloc->new_<IonBuilder>((JSContext *) nullptr,
CompileCompartment::get(cx->compartment()),
temp, graph, constraints,
&inspector, info, baselineFrameInspector);
inspector, info, baselineFrameInspector);
if (!builder)
return AbortReason_Alloc;
@ -1696,28 +1705,6 @@ IonCompile(JSContext *cx, JSScript *script,
RootedScript builderScript(cx, builder->script());
IonSpewNewFunction(graph, builderScript);
mozilla::Maybe<AutoProtectHeapForCompilation> protect;
if (js_IonOptions.checkThreadSafety &&
cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL &&
!cx->runtime()->profilingScripts &&
!cx->runtime()->spsProfiler.enabled())
{
protect.construct(cx->runtime());
}
bool succeeded = builder->build();
builder->clearForBackEnd();
if (!succeeded) {
if (cx->isExceptionPending()) {
IonSpew(IonSpew_Abort, "Builder raised exception.");
return AbortReason_Error;
}
IonSpew(IonSpew_Abort, "Builder failed to build.");
return builder->abortReason();
}
// If possible, compile the script off thread.
if (OffThreadCompilationAvailable(cx)) {
if (recompile) {
@ -1739,6 +1726,24 @@ IonCompile(JSContext *cx, JSScript *script,
return AbortReason_NoAbort;
}
Maybe<AutoEnterIonCompilation> ionCompiling;
ionCompiling.construct();
Maybe<AutoProtectHeapForIonCompilation> protect;
if (js_IonOptions.checkThreadSafety &&
cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL &&
!cx->runtime()->profilingScripts &&
!cx->runtime()->spsProfiler.enabled())
{
protect.construct(cx->runtime());
}
bool succeeded = builder->build();
builder->clearForBackEnd();
if (!succeeded)
return builder->abortReason();
ScopedJSDeletePtr<CodeGenerator> codegen(CompileBackEnd(builder));
if (!codegen) {
IonSpew(IonSpew_Abort, "Failed during back-end compilation.");
@ -1747,6 +1752,7 @@ IonCompile(JSContext *cx, JSScript *script,
if (!protect.empty())
protect.destroy();
ionCompiling.destroy();
bool success = codegen->link(cx, builder->constraints());

Просмотреть файл

@ -222,11 +222,10 @@ IsPhiObservable(MPhi *phi, Observability observe)
if (fun && slot == info.thisSlot())
return true;
// If the function is heavyweight, and the Phi is of the |scopeChain|
// value, and the function may need an arguments object, then make sure
// to preserve the scope chain, because it may be needed to construct the
// arguments object during bailout.
if (fun && fun->isHeavyweight() && info.hasArguments() && slot == info.scopeChainSlot())
// If the function may need an arguments object, then make sure to preserve
// the scope chain, because it may be needed to construct the arguments
// object during bailout.
if (fun && info.hasArguments() && slot == info.scopeChainSlot())
return true;
// If the Phi is one of the formal argument, and we are using an argument
@ -2177,7 +2176,8 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
MIRGraph graph(&temp);
CompileInfo info(script, fun,
/* osrPc = */ nullptr, /* constructing = */ false,
DefinitePropertiesAnalysis);
DefinitePropertiesAnalysis,
script->needsArgsObj());
AutoTempAllocatorRooter root(cx, &temp);

Просмотреть файл

@ -135,16 +135,24 @@ IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp, Tem
lazyArguments_(nullptr),
inlineCallInfo_(nullptr)
{
script_.init(info->script());
script_ = info->script();
pc = info->startPC();
#ifdef DEBUG
lock();
JS_ASSERT(script()->hasBaselineScript());
unlock();
#endif
JS_ASSERT(!!analysisContext == (info->executionMode() == DefinitePropertiesAnalysis));
}
void
IonBuilder::clearForBackEnd()
{
// This case should only be hit if there was a failure while building.
if (!lock_.empty())
lock_.destroy();
JS_ASSERT(!analysisContext);
baselineFrame_ = nullptr;
@ -581,12 +589,16 @@ IonBuilder::pushLoop(CFGState::State initial, jsbytecode *stopAt, MBasicBlock *e
bool
IonBuilder::init()
{
lock();
if (!types::TypeScript::FreezeTypeSets(constraints(), script(),
&thisTypes, &argTypes, &typeArray))
{
return false;
}
unlock();
if (!analysis().init(alloc(), gsn))
return false;
@ -694,6 +706,8 @@ IonBuilder::build()
if (!traverseBytecode())
return false;
unlock();
if (!maybeAddOsrTypeBarriers())
return false;
@ -851,6 +865,7 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
if (!traverseBytecode())
return false;
unlock();
return true;
}
@ -905,6 +920,9 @@ IonBuilder::initParameters()
// interpreter and didn't accumulate type information, try to use that OSR
// frame to determine possible initial types for 'this' and parameters.
// For unknownProperties() tests under addType.
lock();
if (thisTypes->empty() && baselineFrame_) {
if (!thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc()))
return false;
@ -928,6 +946,8 @@ IonBuilder::initParameters()
current->initSlot(info().argSlotUnchecked(i), param);
}
unlock();
return true;
}
@ -950,6 +970,8 @@ IonBuilder::initScopeChain(MDefinition *callee)
if (!script()->compileAndGo())
return abort("non-CNG global scripts are not supported");
lock();
if (JSFunction *fun = info().fun()) {
if (!callee) {
MCallee *calleeIns = MCallee::New(alloc());
@ -975,6 +997,8 @@ IonBuilder::initScopeChain(MDefinition *callee)
scope = constant(ObjectValue(script()->global()));
}
unlock();
current->setScopeChain(scope);
return true;
}
@ -1168,6 +1192,14 @@ IonBuilder::maybeAddOsrTypeBarriers()
bool
IonBuilder::traverseBytecode()
{
// Always hold the compilation lock when traversing bytecode, though release
// it before reacquiring it every few opcodes so that the main thread does not
// block for long when updating compilation data.
lock();
size_t lockOpcodeCount = 0;
static const size_t LOCK_OPCODE_GRANULARITY = 5;
for (;;) {
JS_ASSERT(pc < info().limitPC());
@ -1242,6 +1274,12 @@ IonBuilder::traverseBytecode()
if (!inspectOpcode(op))
return false;
if (++lockOpcodeCount == LOCK_OPCODE_GRANULARITY) {
unlock();
lock();
lockOpcodeCount = 0;
}
#ifdef DEBUG
for (size_t i = 0; i < popped.length(); i++) {
// Call instructions can discard PassArg instructions. Ignore them.
@ -3845,13 +3883,16 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
LifoAlloc *lifoAlloc = alloc_->lifoAlloc();
CompileInfo *info = lifoAlloc->new_<CompileInfo>(calleeScript, target,
(jsbytecode *)nullptr, callInfo.constructing(),
this->info().executionMode());
this->info().executionMode(),
/* needsArgsObj = */ false);
if (!info)
return false;
MIRGraphReturns returns(alloc());
AutoAccumulateReturns aar(graph(), returns);
unlock();
// Build the graph.
IonBuilder inlineBuilder(analysisContext, compartment,
&alloc(), &graph(), constraints(), &inspector, info, nullptr,
@ -3875,6 +3916,8 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
return false;
}
lock();
// Create return block.
jsbytecode *postCall = GetNextPc(pc);
MBasicBlock *returnBlock = newBlock(nullptr, postCall);
@ -4698,7 +4741,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee)
JSObject *templateObject = inspector->getTemplateObject(pc);
if (!templateObject || !templateObject->is<JSObject>())
return nullptr;
if (templateObject->getProto() != proto)
if (!templateObject->hasTenuredProto() || templateObject->getProto() != proto)
return nullptr;
if (!target->nonLazyScript()->types)
@ -5096,6 +5139,8 @@ IonBuilder::testShouldDOMCall(types::TypeSet *inTypes,
if (!curType)
continue;
if (!curType->hasTenuredProto())
return false;
JSObject *proto = curType->proto().toObjectOrNull();
if (!instanceChecker(proto, jinfo->protoID, jinfo->depth))
return false;
@ -6031,6 +6076,8 @@ IonBuilder::testSingletonProperty(JSObject *obj, PropertyName *name)
if (ClassHasResolveHook(compartment, obj->getClass(), name))
return nullptr;
if (!obj->hasTenuredProto())
return nullptr;
obj = obj->getProto();
}
@ -6104,6 +6151,8 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, Pr
if (property.isOwnProperty(constraints()))
return false;
if (!object->hasTenuredProto())
return false;
if (JSObject *proto = object->proto().toObjectOrNull()) {
// Test this type.
if (testSingletonProperty(proto, name) != singleton)
@ -7897,6 +7946,8 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
return false;
}
if (!type->hasTenuredProto())
return false;
JSObject *proto = type->proto().toObjectOrNull();
if (proto == foundProto)
break;
@ -7996,7 +8047,7 @@ IonBuilder::annotateGetPropertyCache(MDefinition *obj, MGetPropertyCache *getPro
if (!baseTypeObj)
continue;
types::TypeObjectKey *typeObj = types::TypeObjectKey::get(baseTypeObj);
if (typeObj->unknownProperties() || !typeObj->proto().isObject())
if (typeObj->unknownProperties() || !typeObj->hasTenuredProto() || !typeObj->proto().isObject())
continue;
const Class *clasp = typeObj->clasp();

Просмотреть файл

@ -724,7 +724,7 @@ class IonBuilder : public MIRGenerator
}
// A builder is inextricably tied to a particular script.
HeapPtrScript script_;
JSScript *script_;
// If off thread compilation is successful, the final code generator is
// attached here. Code has been generated, but not linked (there is not yet
@ -735,7 +735,7 @@ class IonBuilder : public MIRGenerator
public:
void clearForBackEnd();
JSScript *script() const { return script_.get(); }
JSScript *script() const { return script_; }
CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
@ -765,6 +765,17 @@ class IonBuilder : public MIRGenerator
// Constraints for recording dependencies on type information.
types::CompilerConstraintList *constraints_;
mozilla::Maybe<AutoLockForCompilation> lock_;
void lock() {
if (!analysisContext)
lock_.construct(compartment);
}
void unlock() {
if (!analysisContext)
lock_.destroy();
}
// Basic analysis information about the script.
BytecodeAnalysis analysis_;
BytecodeAnalysis &analysis() {

Просмотреть файл

@ -468,7 +468,7 @@ GeneratePrototypeGuards(JSContext *cx, IonScript *ion, MacroAssembler &masm, JSO
// Note: objectReg and scratchReg may be the same register, so we cannot
// use objectReg in the rest of this function.
masm.loadPtr(Address(objectReg, JSObject::offsetOfType()), scratchReg);
Address proto(scratchReg, offsetof(types::TypeObject, proto));
Address proto(scratchReg, types::TypeObject::offsetOfProto());
masm.branchNurseryPtr(Assembler::NotEqual, proto,
ImmMaybeNurseryPtr(obj->getProto()), failures);
}
@ -796,11 +796,7 @@ GenerateReadSlot(JSContext *cx, IonScript *ion, MacroAssembler &masm,
Register lastReg = object;
JS_ASSERT(scratchReg != object);
while (proto) {
Address addrType(lastReg, JSObject::offsetOfType());
masm.loadPtr(addrType, scratchReg);
Address addrProto(scratchReg, offsetof(types::TypeObject, proto));
masm.loadPtr(addrProto, scratchReg);
Address addrShape(scratchReg, JSObject::offsetOfShape());
masm.loadObjProto(lastReg, scratchReg);
// Guard the shape of the current prototype.
masm.branchPtr(Assembler::NotEqual,
@ -2584,8 +2580,7 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
Shape *protoShape = proto->lastProperty();
// load next prototype
masm.loadPtr(Address(protoReg, JSObject::offsetOfType()), protoReg);
masm.loadPtr(Address(protoReg, offsetof(types::TypeObject, proto)), protoReg);
masm.loadObjProto(protoReg, protoReg);
// Ensure that its shape matches.
masm.branchTestObjShape(Assembler::NotEqual, protoReg, protoShape, &failuresPopObject);

Просмотреть файл

@ -292,12 +292,12 @@ class MacroAssembler : public MacroAssemblerSpecific
}
void loadObjClass(Register objReg, Register dest) {
loadPtr(Address(objReg, JSObject::offsetOfType()), dest);
loadPtr(Address(dest, offsetof(types::TypeObject, clasp)), dest);
loadPtr(Address(dest, types::TypeObject::offsetOfClasp()), dest);
}
void branchTestObjClass(Condition cond, Register obj, Register scratch, const js::Class *clasp,
Label *label) {
loadPtr(Address(obj, JSObject::offsetOfType()), scratch);
branchPtr(cond, Address(scratch, offsetof(types::TypeObject, clasp)), ImmPtr(clasp), label);
branchPtr(cond, Address(scratch, types::TypeObject::offsetOfClasp()), ImmPtr(clasp), label);
}
void branchTestObjShape(Condition cond, Register obj, const Shape *shape, Label *label) {
branchPtr(cond, Address(obj, JSObject::offsetOfShape()), ImmGCPtr(shape), label);
@ -353,7 +353,7 @@ class MacroAssembler : public MacroAssemblerSpecific
void loadObjProto(Register obj, Register dest) {
loadPtr(Address(obj, JSObject::offsetOfType()), dest);
loadPtr(Address(dest, offsetof(types::TypeObject, proto)), dest);
loadPtr(Address(dest, types::TypeObject::offsetOfProto()), dest);
}
void loadStringLength(Register str, Register dest) {

Просмотреть файл

@ -2929,7 +2929,13 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
// If this access has never executed, try to add types to the observed set
// according to any property which exists on the object or its prototype.
if (updateObserved && observed->empty() && name) {
JSObject *obj = object->singleton() ? object->singleton() : object->proto().toObjectOrNull();
JSObject *obj;
if (object->singleton())
obj = object->singleton();
else if (object->hasTenuredProto())
obj = object->proto().toObjectOrNull();
else
obj = nullptr;
while (obj) {
if (!obj->getClass()->isNative())
@ -2953,6 +2959,8 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
}
}
if (!obj->hasTenuredProto())
break;
obj = obj->getProto();
}
}
@ -3004,7 +3012,11 @@ jit::PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *cons
types::TypeObjectKey *object = types->getObject(i);
if (!object)
continue;
while (object->proto().isObject()) {
while (true) {
if (!object->hasTenuredProto())
return true;
if (!object->proto().isObject())
break;
object = types::TypeObjectKey::get(object->proto().toObject());
if (PropertyReadNeedsTypeBarrier(constraints, object, name, observed))
return true;

Просмотреть файл

@ -106,7 +106,7 @@ MapSlotsToBitset(BitSet *set, CompactBufferWriter &stream, uint32_t nslots, uint
}
size_t count = set->rawLength();
uint32_t *words = set->raw();
const uint32_t *words = set->raw();
for (size_t i = 0; i < count; i++)
stream.writeUnsigned(words[i]);
}

Просмотреть файл

@ -552,7 +552,7 @@ OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out)
bool
GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval)
{
if (!cx->global()->getIntrinsicValue(cx, name, rval))
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, rval))
return false;
// This function is called when we try to compile a cold getintrinsic
@ -946,7 +946,7 @@ AssertValidObjectPtr(JSContext *cx, JSObject *obj)
JS_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
JS_ASSERT_IF(!obj->hasLazyType(),
obj->type()->clasp == obj->lastProperty()->getObjectClass());
obj->type()->clasp() == obj->lastProperty()->getObjectClass());
if (obj->isTenured()) {
JS_ASSERT(obj->isAligned());

Просмотреть файл

@ -1725,7 +1725,7 @@ CodeGeneratorX86Shared::visitGuardClass(LGuardClass *guard)
Register tmp = ToRegister(guard->tempInt());
masm.loadPtr(Address(obj, JSObject::offsetOfType()), tmp);
masm.cmpPtr(Operand(tmp, offsetof(types::TypeObject, clasp)), ImmPtr(guard->mir()->getClass()));
masm.cmpPtr(Operand(tmp, types::TypeObject::offsetOfClasp()), ImmPtr(guard->mir()->getClass()));
if (!bailoutIf(Assembler::NotEqual, guard->snapshot()))
return false;
return true;

Просмотреть файл

@ -391,7 +391,7 @@ MSG_DEF(JSMSG_DATE_NOT_FINITE, 337, 0, JSEXN_RANGEERR, "date value is not
MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 338, 0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body")
MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL, 339, 1, JSEXN_TYPEERR, "asm.js type error: {0}")
MSG_DEF(JSMSG_USE_ASM_LINK_FAIL, 340, 1, JSEXN_TYPEERR, "asm.js link error: {0}")
MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 341, 1, JSEXN_ERR, "successfully compiled asm.js code ({0})")
MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 341, 1, JSEXN_NONE, "Successfully compiled asm.js code ({0})")
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 342, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
MSG_DEF(JSMSG_YIELD_IN_ARROW, 343, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield")
MSG_DEF(JSMSG_WRONG_VALUE, 344, 2, JSEXN_ERR, "expected {0} but found {1}")

Просмотреть файл

@ -700,9 +700,7 @@ StartRequest(JSContext *cx)
} else {
/* Indicate that a request is running. */
rt->requestDepth = 1;
if (rt->activityCallback)
rt->activityCallback(rt->activityCallbackArg, true);
rt->triggerActivityCallback(true);
}
}
@ -718,9 +716,7 @@ StopRequest(JSContext *cx)
} else {
rt->conservativeGC.updateForRequestEnd();
rt->requestDepth = 0;
if (rt->activityCallback)
rt->activityCallback(rt->activityCallbackArg, false);
rt->triggerActivityCallback(false);
}
}
#endif /* JS_THREADSAFE */

Просмотреть файл

@ -116,6 +116,7 @@ js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction
JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite());
JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope());
JS_ASSERT(types::UseNewTypeForClone(fun));
JS_ASSERT(CurrentThreadCanReadCompilationData());
/*
* If we start allocating function objects in the nursery, then the callsite
@ -126,7 +127,7 @@ js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction
if (!table.initialized())
return nullptr;
CallsiteCloneTable::Ptr p = table.lookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc)));
CallsiteCloneTable::Ptr p = table.readonlyThreadsafeLookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc)));
if (p)
return p->value();
@ -153,6 +154,8 @@ js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript scri
typedef CallsiteCloneKey Key;
typedef CallsiteCloneTable Table;
AutoLockForCompilation lock(cx);
Table &table = cx->compartment()->callsiteClones;
if (!table.initialized() && !table.init())
return nullptr;

Просмотреть файл

@ -32,7 +32,10 @@ js_ReportOverRecursed(js::ThreadSafeContext *cx);
namespace js {
namespace jit { class IonContext; }
namespace jit {
class IonContext;
class CompileCompartment;
}
struct CallsiteCloneKey {
/* The original function that we are cloning. */
@ -1038,7 +1041,9 @@ class AutoLockForExclusiveAccess
if (runtime->numExclusiveThreads) {
runtime->assertCanLock(JSRuntime::ExclusiveAccessLock);
PR_Lock(runtime->exclusiveAccessLock);
#ifdef DEBUG
runtime->exclusiveAccessOwner = PR_GetCurrentThread();
#endif
} else {
JS_ASSERT(!runtime->mainThreadHasExclusiveAccess);
runtime->mainThreadHasExclusiveAccess = true;
@ -1057,9 +1062,7 @@ class AutoLockForExclusiveAccess
~AutoLockForExclusiveAccess() {
if (runtime->numExclusiveThreads) {
JS_ASSERT(runtime->exclusiveAccessOwner == PR_GetCurrentThread());
#ifdef DEBUG
runtime->exclusiveAccessOwner = nullptr;
#endif
PR_Unlock(runtime->exclusiveAccessLock);
} else {
JS_ASSERT(runtime->mainThreadHasExclusiveAccess);
@ -1083,6 +1086,69 @@ class AutoLockForExclusiveAccess
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class AutoLockForCompilation
{
#ifdef JS_WORKER_THREADS
JSRuntime *runtime;
void init(JSRuntime *rt) {
runtime = rt;
if (runtime->numCompilationThreads) {
runtime->assertCanLock(JSRuntime::CompilationLock);
PR_Lock(runtime->compilationLock);
#ifdef DEBUG
runtime->compilationLockOwner = PR_GetCurrentThread();
#endif
} else {
#ifdef DEBUG
JS_ASSERT(!runtime->mainThreadHasCompilationLock);
runtime->mainThreadHasCompilationLock = true;
#endif
}
}
public:
AutoLockForCompilation(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (cx->isJSContext())
init(cx->asJSContext()->runtime());
else
runtime = nullptr;
}
AutoLockForCompilation(jit::CompileCompartment *compartment MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
~AutoLockForCompilation() {
if (runtime) {
if (runtime->numCompilationThreads) {
JS_ASSERT(runtime->compilationLockOwner == PR_GetCurrentThread());
#ifdef DEBUG
runtime->compilationLockOwner = nullptr;
#endif
PR_Unlock(runtime->compilationLock);
} else {
#ifdef DEBUG
JS_ASSERT(runtime->mainThreadHasCompilationLock);
runtime->mainThreadHasCompilationLock = false;
#endif
}
}
}
#else // JS_WORKER_THREADS
public:
AutoLockForCompilation(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
AutoLockForCompilation(jit::CompileCompartment *compartment MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
~AutoLockForCompilation() {
// An empty destructor is needed to avoid warnings from clang about
// unused local variables of this type.
}
#endif // JS_WORKER_THREADS
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
} /* namespace js */
#ifdef _MSC_VER

Просмотреть файл

@ -338,7 +338,7 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin
return true;
}
RootedObject proto(cx, Proxy::LazyProto);
RootedObject proto(cx, TaggedProto::LazyProto);
RootedObject existing(cx, existingArg);
if (existing) {
/* Is it possible to reuse |existing|? */

Просмотреть файл

@ -1124,25 +1124,21 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
// THING_ROOT_LAZY_SCRIPT).
AutoSuppressGC suppressGC(cx);
fun->flags_ &= ~INTERPRETED_LAZY;
fun->flags_ |= INTERPRETED;
RootedScript script(cx, lazy->maybeScript());
if (script) {
fun->initScript(script);
AutoLockForCompilation lock(cx);
fun->setUnlazifiedScript(script);
return true;
}
fun->initScript(nullptr);
if (fun != lazy->function()) {
script = lazy->function()->getOrCreateScript(cx);
if (!script) {
fun->initLazyScript(lazy);
if (!script)
return false;
}
fun->initScript(script);
AutoLockForCompilation lock(cx);
fun->setUnlazifiedScript(script);
return true;
}
@ -1162,17 +1158,19 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
if (script) {
RootedObject enclosingScope(cx, lazy->enclosingScope());
RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script));
if (!clonedScript) {
fun->initLazyScript(lazy);
if (!clonedScript)
return false;
}
clonedScript->setSourceObject(lazy->sourceObject());
fun->initAtom(script->function()->displayAtom());
fun->initScript(clonedScript);
clonedScript->setFunction(fun);
{
AutoLockForCompilation lock(cx);
fun->setUnlazifiedScript(clonedScript);
}
CallNewScriptHook(cx, clonedScript, fun);
lazy->initScript(clonedScript);
@ -1184,18 +1182,14 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
// Parse and compile the script from source.
SourceDataCache::AutoSuppressPurge asp(cx);
const jschar *chars = lazy->source()->chars(cx, asp);
if (!chars) {
fun->initLazyScript(lazy);
if (!chars)
return false;
}
const jschar *lazyStart = chars + lazy->begin();
size_t lazyLength = lazy->end() - lazy->begin();
if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength)) {
fun->initLazyScript(lazy);
if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength))
return false;
}
script = fun->nonLazyScript();

Просмотреть файл

@ -123,8 +123,6 @@ class JSFunction : public JSObject
/* Possible attributes of an interpreted function: */
bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; }
bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; }
bool hasScript() const { return flags() & INTERPRETED; }
bool isExprClosure() const { return flags() & EXPR_CLOSURE; }
bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; }
bool isLambda() const { return flags() & LAMBDA; }
@ -136,6 +134,17 @@ class JSFunction : public JSObject
return flags() & SH_WRAPPABLE;
}
// Functions can change between being lazily interpreted and having scripts
// when under the compilation lock.
bool isInterpretedLazy() const {
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
return flags() & INTERPRETED_LAZY;
}
bool hasScript() const {
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
return flags() & INTERPRETED;
}
bool hasJITCode() const {
if (!hasScript())
return false;
@ -321,6 +330,7 @@ class JSFunction : public JSObject
JSScript *nonLazyScript() const {
JS_ASSERT(hasScript());
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
return u.i.s.script_;
}
@ -331,11 +341,13 @@ class JSFunction : public JSObject
js::LazyScript *lazyScript() const {
JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
return u.i.s.lazy_;
}
js::LazyScript *lazyScriptOrNull() const {
JS_ASSERT(isInterpretedLazy());
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
return u.i.s.lazy_;
}
@ -357,15 +369,25 @@ class JSFunction : public JSObject
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
void setScript(JSScript *script_) {
JS_ASSERT(isInterpreted());
JS_ASSERT(hasScript());
mutableScript() = script_;
}
void initScript(JSScript *script_) {
JS_ASSERT(isInterpreted());
JS_ASSERT(hasScript());
mutableScript().init(script_);
}
void setUnlazifiedScript(JSScript *script) {
// Note: createScriptForLazilyInterpretedFunction triggers a barrier on
// lazy script before it is overwritten here.
JS_ASSERT(js::CurrentThreadCanWriteCompilationData());
JS_ASSERT(isInterpretedLazy());
flags_ &= ~INTERPRETED_LAZY;
flags_ |= INTERPRETED;
initScript(script);
}
void initLazyScript(js::LazyScript *lazy) {
JS_ASSERT(isInterpreted());
flags_ &= ~INTERPRETED;

Просмотреть файл

@ -5520,6 +5520,12 @@ AutoSuppressGC::AutoSuppressGC(JSCompartment *comp)
suppressGC_++;
}
AutoSuppressGC::AutoSuppressGC(JSRuntime *rt)
: suppressGC_(rt->mainThread.suppressGC)
{
suppressGC_++;
}
bool
js::UninlinedIsInsideNursery(JSRuntime *rt, const void *thing)
{

Просмотреть файл

@ -1398,6 +1398,7 @@ class AutoSuppressGC
public:
AutoSuppressGC(ExclusiveContext *cx);
AutoSuppressGC(JSCompartment *comp);
AutoSuppressGC(JSRuntime *rt);
~AutoSuppressGC()
{

Просмотреть файл

@ -685,6 +685,8 @@ TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script
TemporaryTypeSet **pArgTypes,
TemporaryTypeSet **pBytecodeTypes)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
LifoAlloc *alloc = constraints->alloc();
StackTypeSet *existing = script->types->typeArray();
@ -791,13 +793,26 @@ CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileIn
const Class *
TypeObjectKey::clasp()
{
return isTypeObject() ? asTypeObject()->clasp : asSingleObject()->getClass();
return isTypeObject() ? asTypeObject()->clasp() : asSingleObject()->getClass();
}
TaggedProto
TypeObjectKey::proto()
{
return isTypeObject() ? TaggedProto(asTypeObject()->proto) : asSingleObject()->getTaggedProto();
JS_ASSERT(hasTenuredProto());
return isTypeObject() ? asTypeObject()->proto() : asSingleObject()->getTaggedProto();
}
bool
ObjectImpl::hasTenuredProto() const
{
return type_->hasTenuredProto();
}
bool
TypeObjectKey::hasTenuredProto()
{
return isTypeObject() ? asTypeObject()->hasTenuredProto() : asSingleObject()->hasTenuredProto();
}
JSObject *
@ -836,6 +851,7 @@ HeapTypeSetKey
TypeObjectKey::property(jsid id)
{
JS_ASSERT(!unknownProperties());
JS_ASSERT(CurrentThreadCanReadCompilationData());
HeapTypeSetKey property;
property.object_ = this;
@ -1429,8 +1445,10 @@ ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnkno
HeapTypeSet *types = object->maybeGetProperty(JSID_EMPTY);
/* Mark as unknown after getting the types, to avoid assertion. */
if (markingUnknown)
object->flags |= OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES;
if (markingUnknown) {
AutoLockForCompilation lock(cxArg);
object->addFlags(OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES);
}
if (types) {
if (JSContext *cx = cxArg->maybeJSContext()) {
@ -1678,6 +1696,9 @@ TemporaryTypeSet::getCommonPrototype()
if (!object)
continue;
if (!object->hasTenuredProto())
return nullptr;
TaggedProto nproto = object->proto();
if (proto) {
if (nproto != proto)
@ -1737,18 +1758,24 @@ TypeZone::init(JSContext *cx)
}
TypeObject *
TypeCompartment::newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto, bool unknown)
TypeCompartment::newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto,
TypeObjectFlags initialFlags)
{
JS_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject()));
if (!cx->typeInferenceEnabled())
initialFlags |= OBJECT_FLAG_UNKNOWN_MASK;
if (cx->isJSContext()) {
if (proto.isObject() && IsInsideNursery(cx->asJSContext()->runtime(), proto.toObject()))
initialFlags |= OBJECT_FLAG_NURSERY_PROTO;
}
TypeObject *object = gc::NewGCThing<TypeObject, CanGC>(cx, gc::FINALIZE_TYPE_OBJECT,
sizeof(TypeObject), gc::TenuredHeap);
if (!object)
return nullptr;
new(object) TypeObject(clasp, proto, unknown);
if (!cx->typeInferenceEnabled())
object->flags |= OBJECT_FLAG_UNKNOWN_MASK;
new(object) TypeObject(clasp, proto, initialFlags);
return object;
}
@ -1871,12 +1898,11 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
return nullptr;
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
res = newTypeObject(cx, GetClassForProtoKey(key.kind), tagged);
res = newTypeObject(cx, GetClassForProtoKey(key.kind), tagged, OBJECT_FLAG_FROM_ALLOCATION_SITE);
if (!res) {
cx->compartment()->types.setPendingNukeTypes(cx);
return nullptr;
}
res->flags |= OBJECT_FLAG_FROM_ALLOCATION_SITE;
key.script = keyScript;
}
@ -2010,6 +2036,8 @@ PrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSObject *obj)
HeapTypeSetKey index = type->property(JSID_VOID);
if (index.configured(constraints) || index.isOwnProperty(constraints))
return true;
if (!obj->hasTenuredProto())
return true;
obj = obj->getProto();
} while (obj);
@ -2175,10 +2203,9 @@ void
TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
{
JS_ASSERT(this == &cx->compartment()->types);
JS_ASSERT(!(target->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN));
JS_ASSERT(!(target->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN));
JS_ASSERT(!target->singleton);
JS_ASSERT(target->unknownProperties());
target->flags |= OBJECT_FLAG_SETS_MARKED_UNKNOWN;
AutoEnterAnalysis enter(cx);
@ -2219,6 +2246,9 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
}
}
}
AutoLockForCompilation lock(cx);
target->addFlags(OBJECT_FLAG_SETS_MARKED_UNKNOWN);
}
void
@ -2511,7 +2541,7 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(lookup);
if (p) {
JS_ASSERT(obj->getProto() == p->value().object->proto);
JS_ASSERT(obj->getProto() == p->value().object->proto().toObject());
JS_ASSERT(obj->lastProperty() == p->value().shape);
UpdateObjectTableEntryTypes(cx, p->value(), properties.begin(), properties.length());
@ -2614,7 +2644,7 @@ TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t n
cx->clearPendingException();
return nullptr;
}
JS_ASSERT(obj->getProto() == p->value().object->proto);
JS_ASSERT(obj->getProto() == p->value().object->proto().toObject());
RootedShape shape(cx, p->value().shape);
if (!JSObject::setLastProperty(cx, obj, shape)) {
@ -2635,6 +2665,36 @@ TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t n
// TypeObject
/////////////////////////////////////////////////////////////////////
#ifdef DEBUG
void
TypeObject::assertCanAccessProto()
{
// The proto pointer for type objects representing singletons may move.
JS_ASSERT_IF(singleton, CurrentThreadCanReadCompilationData());
// Any proto pointer which is in the nursery may be moved, and may not be
// accessed during off thread compilation.
#if defined(JSGC_GENERATIONAL) && defined(JS_WORKER_THREADS)
PerThreadData *pt = TlsPerThreadData.get();
TaggedProto proto(proto_);
JS_ASSERT_IF(proto.isObject() && !proto.toObject()->isTenured(),
!pt || !pt->ionCompiling);
#endif
}
#endif // DEBUG
void
TypeObject::setProto(JSContext *cx, TaggedProto proto)
{
JS_ASSERT(CurrentThreadCanWriteCompilationData());
JS_ASSERT(singleton);
if (proto.isObject() && IsInsideNursery(cx->runtime(), proto.toObject()))
addFlags(OBJECT_FLAG_NURSERY_PROTO);
setProtoUnchecked(proto);
}
static inline void
UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shape *shape,
bool indexed)
@ -2644,7 +2704,8 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap
if (shape->hasGetterValue() || shape->hasSetterValue()) {
types->setConfiguredProperty(cx);
types->addType(cx, Type::UnknownType());
if (!types->TypeSet::addType(Type::UnknownType(), &cx->typeLifoAlloc()))
cx->compartment()->types.setPendingNukeTypes(cx);
} else if (shape->hasDefaultGetter() && shape->hasSlot()) {
if (!indexed && types->canSetDefinite(shape->slot()))
types->setDefinite(shape->slot());
@ -2658,7 +2719,8 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap
*/
if (indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) {
Type type = GetValueType(value);
types->addType(cx, type);
if (!types->TypeSet::addType(type, &cx->typeLifoAlloc()))
cx->compartment()->types.setPendingNukeTypes(cx);
}
}
}
@ -2696,7 +2758,8 @@ TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop)
const Value &value = singleton->getDenseElement(i);
if (!value.isMagic(JS_ELEMENTS_HOLE)) {
Type type = GetValueType(value);
base->types.addType(cx, type);
if (!base->types.TypeSet::addType(type, &cx->typeLifoAlloc()))
cx->compartment()->types.setPendingNukeTypes(cx);
}
}
} else if (!JSID_IS_EMPTY(id)) {
@ -2871,7 +2934,7 @@ TypeObject::markStateChange(ExclusiveContext *cxArg)
void
TypeObject::setFlags(ExclusiveContext *cx, TypeObjectFlags flags)
{
if ((this->flags & flags) == flags)
if (hasAllFlags(flags))
return;
AutoEnterAnalysis enter(cx);
@ -2882,7 +2945,10 @@ TypeObject::setFlags(ExclusiveContext *cx, TypeObjectFlags flags)
singleton->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
}
this->flags |= flags;
{
AutoLockForCompilation lock(cx);
addFlags(flags);
}
InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeObjectString(this), flags);
@ -2897,7 +2963,7 @@ TypeObject::markUnknown(ExclusiveContext *cx)
JS_ASSERT(cx->compartment()->activeAnalysis);
JS_ASSERT(!unknownProperties());
if (!(flags & OBJECT_FLAG_ADDENDUM_CLEARED))
if (!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED))
clearAddendum(cx);
InferSpew(ISpewOps, "UnknownProperties: %s", TypeObjectString(this));
@ -2926,8 +2992,11 @@ TypeObject::markUnknown(ExclusiveContext *cx)
void
TypeObject::clearAddendum(ExclusiveContext *cx)
{
JS_ASSERT(!(flags & OBJECT_FLAG_ADDENDUM_CLEARED));
flags |= OBJECT_FLAG_ADDENDUM_CLEARED;
JS_ASSERT(!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED));
{
AutoLockForCompilation lock(cx);
addFlags(OBJECT_FLAG_ADDENDUM_CLEARED);
}
/*
* It is possible for the object to not have a new script or other
@ -3072,11 +3141,11 @@ TypeObject::clearTypedObjectAddendum(ExclusiveContext *cx)
void
TypeObject::print()
{
TaggedProto tagged(proto);
TaggedProto tagged(proto());
fprintf(stderr, "%s : %s",
TypeObjectString(this),
tagged.isObject() ? TypeString(Type::ObjectType(proto))
: (tagged.isLazy() ? "(lazy)" : "(null)"));
TypeObjectString(this),
tagged.isObject() ? TypeString(Type::ObjectType(tagged.toObject()))
: (tagged.isLazy() ? "(lazy)" : "(null)"));
if (unknownProperties()) {
fprintf(stderr, " unknown");
@ -3142,7 +3211,7 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint
* non-writable, both of which are indicated by the source type set
* being marked as configured.
*/
if (!(object->flags & OBJECT_FLAG_ADDENDUM_CLEARED) && source->configuredProperty())
if (!(object->flags() & OBJECT_FLAG_ADDENDUM_CLEARED) && source->configuredProperty())
object->clearAddendum(cx);
}
@ -3166,7 +3235,7 @@ types::AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *
* a permanent property in any transitive prototype, the definite
* properties get cleared from the type.
*/
RootedObject parent(cx, type->proto);
RootedObject parent(cx, type->proto().toObjectOrNull());
while (parent) {
TypeObject *parentObject = parent->getType(cx);
if (!parentObject || parentObject->unknownProperties())
@ -3196,7 +3265,7 @@ class TypeConstraintClearDefiniteSingle : public TypeConstraint
const char *kind() { return "clearDefiniteSingle"; }
void newType(JSContext *cx, TypeSet *source, Type type) {
if (object->flags & OBJECT_FLAG_ADDENDUM_CLEARED)
if (object->flags() & OBJECT_FLAG_ADDENDUM_CLEARED)
return;
if (source->baseFlags() || source->getObjectCount() > 1)
@ -3279,9 +3348,9 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
}
if (baseobj->slotSpan() == 0 ||
!!(type->flags & OBJECT_FLAG_ADDENDUM_CLEARED))
!!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED))
{
if (type->addendum)
if (type->hasNewScript())
type->clearAddendum(cx);
return;
}
@ -3296,8 +3365,8 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
type->clearAddendum(cx);
return;
}
JS_ASSERT(!type->addendum);
JS_ASSERT(!(type->flags & OBJECT_FLAG_ADDENDUM_CLEARED));
JS_ASSERT(!type->hasNewScript());
JS_ASSERT(!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED));
gc::AllocKind kind = gc::GetGCObjectKind(baseobj->slotSpan());
@ -3336,7 +3405,11 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
newScript = (TypeNewScript *) cx->calloc_(numBytes);
#endif
new (newScript) TypeNewScript();
type->addendum = newScript;
{
AutoLockForCompilation lock(cx);
type->setAddendum(newScript);
}
if (!newScript) {
cx->compartment()->types.setPendingNukeTypes(cx);
@ -3633,8 +3706,11 @@ JSObject::splicePrototype(JSContext *cx, const Class *clasp, Handle<TaggedProto>
return true;
}
type->clasp = clasp;
type->proto = proto.raw();
{
AutoLockForCompilation lock(cx);
type->setClasp(clasp);
type->setProto(cx, proto);
}
return true;
}
@ -3651,8 +3727,22 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj)
if (!fun->getOrCreateScript(cx))
return nullptr;
}
// Find flags which need to be specified immediately on the object.
// Don't track whether singletons are packed.
TypeObjectFlags initialFlags = OBJECT_FLAG_NON_PACKED;
if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
initialFlags |= OBJECT_FLAG_ITERATED;
if (obj->isIndexed())
initialFlags |= OBJECT_FLAG_SPARSE_INDEXES;
if (obj->is<ArrayObject>() && obj->as<ArrayObject>().length() > INT32_MAX)
initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW;
Rooted<TaggedProto> proto(cx, obj->getTaggedProto());
TypeObject *type = cx->compartment()->types.newTypeObject(cx, obj->getClass(), proto);
TypeObject *type = cx->compartment()->types.newTypeObject(cx, obj->getClass(), proto, initialFlags);
if (!type) {
if (cx->typeInferenceEnabled())
cx->compartment()->types.setPendingNukeTypes(cx);
@ -3674,24 +3764,10 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj)
if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
type->interpretedFunction = &obj->as<JSFunction>();
if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
type->flags |= OBJECT_FLAG_ITERATED;
/*
* Adjust flags for objects which will have the wrong flags set by just
* looking at the class prototype key.
*/
/* Don't track whether singletons are packed. */
type->flags |= OBJECT_FLAG_NON_PACKED;
if (obj->isIndexed())
type->flags |= OBJECT_FLAG_SPARSE_INDEXES;
if (obj->is<ArrayObject>() && obj->as<ArrayObject>().length() > INT32_MAX)
type->flags |= OBJECT_FLAG_LENGTH_OVERFLOW;
obj->type_ = type;
{
AutoLockForCompilation lock(cx);
obj->type_ = type;
}
return type;
}
@ -3707,8 +3783,8 @@ TypeObjectWithNewScriptEntry::hash(const Lookup &lookup)
/* static */ inline bool
TypeObjectWithNewScriptEntry::match(const TypeObjectWithNewScriptEntry &key, const Lookup &lookup)
{
return key.object->proto == lookup.matchProto.raw() &&
key.object->clasp == lookup.clasp &&
return key.object->proto() == lookup.matchProto &&
key.object->clasp() == lookup.clasp &&
key.newFunction == lookup.newFunction;
}
@ -3805,8 +3881,8 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
newTypeObjects.lookupForAdd(TypeObjectWithNewScriptSet::Lookup(clasp, proto, fun));
if (p) {
TypeObject *type = p->object;
JS_ASSERT(type->clasp == clasp);
JS_ASSERT(type->proto.get() == proto.raw());
JS_ASSERT(type->clasp() == clasp);
JS_ASSERT(type->proto() == proto);
JS_ASSERT_IF(type->hasNewScript(), type->newScript()->fun == fun);
return type;
}
@ -3816,13 +3892,19 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
if (proto.isObject() && !proto.toObject()->setDelegate(this))
return nullptr;
bool markUnknown =
proto.isObject()
? proto.toObject()->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN)
: true;
TypeObjectFlags initialFlags = 0;
if (!proto.isObject() || proto.toObject()->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN)) {
// The new type is not present in any type sets, so mark the object as
// unknown in all type sets it appears in. This allows the prototype of
// such objects to mutate freely without triggering an expensive walk of
// the compartment's type sets. (While scripts normally don't mutate
// __proto__, the browser will for proxies and such, and we need to
// accommodate this behavior).
initialFlags = OBJECT_FLAG_UNKNOWN_MASK | OBJECT_FLAG_SETS_MARKED_UNKNOWN;
}
Rooted<TaggedProto> protoRoot(this, proto);
TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot, markUnknown);
TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot, initialFlags);
if (!type)
return nullptr;
@ -3872,17 +3954,6 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
}
}
/*
* The new type is not present in any type sets, so mark the object as
* unknown in all type sets it appears in. This allows the prototype of
* such objects to mutate freely without triggering an expensive walk of
* the compartment's type sets. (While scripts normally don't mutate
* __proto__, the browser will for proxies and such, and we need to
* accommodate this behavior).
*/
if (type->unknownProperties())
type->flags |= OBJECT_FLAG_SETS_MARKED_UNKNOWN;
return type;
}
@ -3907,7 +3978,7 @@ ExclusiveContext::getLazyType(const Class *clasp, TaggedProto proto)
}
Rooted<TaggedProto> protoRoot(this, proto);
TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot, false);
TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot);
if (!type)
return nullptr;
@ -4159,8 +4230,8 @@ JSCompartment::sweepNewTypeObjectTable(TypeObjectWithNewScriptSet &table)
} else if (entry.newFunction && IsObjectAboutToBeFinalized(&entry.newFunction)) {
e.removeFront();
} else if (entry.object != e.front().object) {
TypeObjectWithNewScriptSet::Lookup lookup(entry.object->clasp,
entry.object->proto.get(),
TypeObjectWithNewScriptSet::Lookup lookup(entry.object->clasp(),
entry.object->proto(),
entry.newFunction);
e.rekeyFront(lookup, entry);
}
@ -4428,7 +4499,7 @@ TypeObject::addTypedObjectAddendum(JSContext *cx,
JS_ASSERT(repr);
if (flags & OBJECT_FLAG_ADDENDUM_CLEARED)
if (flags() & OBJECT_FLAG_ADDENDUM_CLEARED)
return true;
JS_ASSERT(!unknownProperties());

Просмотреть файл

@ -25,20 +25,38 @@
namespace js {
#ifdef DEBUG
bool CurrentThreadCanWriteCompilationData();
bool CurrentThreadCanReadCompilationData();
#endif
class TypeRepresentation;
class TaggedProto
{
public:
static JSObject * const LazyProto;
TaggedProto() : proto(nullptr) {}
TaggedProto(JSObject *proto) : proto(proto) {}
uintptr_t toWord() const { return uintptr_t(proto); }
inline bool isLazy() const;
inline bool isObject() const;
inline JSObject *toObject() const;
inline JSObject *toObjectOrNull() const;
bool isLazy() const {
return proto == LazyProto;
}
bool isObject() const {
/* Skip nullptr and LazyProto. */
return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
}
JSObject *toObject() const {
JS_ASSERT(isObject());
return proto;
}
JSObject *toObjectOrNull() const {
JS_ASSERT(!proto || isObject());
return proto;
}
JSObject *raw() const { return proto; }
bool operator ==(const TaggedProto &other) { return proto == other.proto; }
@ -77,10 +95,10 @@ class TaggedProtoOperations
public:
uintptr_t toWord() const { return value()->toWord(); }
inline bool isLazy() const;
inline bool isObject() const;
inline JSObject *toObject() const;
inline JSObject *toObjectOrNull() const;
inline bool isLazy() const { return value()->isLazy(); }
inline bool isObject() const { return value()->isObject(); }
inline JSObject *toObject() const { return value()->toObject(); }
inline JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); }
JSObject *raw() const { return value()->raw(); }
};
@ -383,6 +401,12 @@ enum MOZ_ENUM_TYPE(uint32_t) {
/* If set, addendum information should not be installed on this object. */
OBJECT_FLAG_ADDENDUM_CLEARED = 0x2,
/*
* If set, the object's prototype might be in the nursery and can't be
* used during Ion compilation (which may be occurring off thread).
*/
OBJECT_FLAG_NURSERY_PROTO = 0x4,
/*
* Whether we have ensured all type sets in the compartment contain
* ANYOBJECT instead of this object.
@ -503,7 +527,7 @@ class TypeSet
static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
/* Add a type to this set using the specified allocator. */
inline bool addType(Type type, LifoAlloc *alloc, bool *padded = nullptr);
inline bool addType(Type type, LifoAlloc *alloc);
/* Get a list of all types in this set. */
typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
@ -857,11 +881,45 @@ struct TypeTypedObject : public TypeObjectAddendum
/* Type information about an object accessed by a script. */
struct TypeObject : gc::BarrieredCell<TypeObject>
{
/* Class shared by objects using this type. */
const Class *clasp;
private:
/* Class shared by object using this type. */
const Class *clasp_;
/* Prototype shared by objects using this type. */
HeapPtrObject proto;
HeapPtrObject proto_;
#ifdef DEBUG
void assertCanAccessProto();
#else
void assertCanAccessProto() {}
#endif
public:
const Class *clasp() {
return clasp_;
}
void setClasp(const Class *clasp) {
JS_ASSERT(CurrentThreadCanWriteCompilationData());
JS_ASSERT(singleton);
clasp_ = clasp;
}
TaggedProto proto() {
assertCanAccessProto();
return TaggedProto(proto_);
}
HeapPtrObject &protoRaw() {
// For use during marking, don't call otherwise.
return proto_;
}
void setProto(JSContext *cx, TaggedProto proto);
void setProtoUnchecked(TaggedProto proto) {
proto_ = proto.raw();
}
/*
* Whether there is a singleton JS object with this type. That JS object
@ -877,8 +935,9 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
static const size_t LAZY_SINGLETON = 1;
bool lazy() const { return singleton == (JSObject *) LAZY_SINGLETON; }
private:
/* Flags for this object. */
TypeObjectFlags flags;
TypeObjectFlags flags_;
/*
* This field allows various special classes of objects to attach
@ -891,23 +950,48 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
* before the object escapes.
*/
HeapPtr<TypeObjectAddendum> addendum;
public:
TypeObjectFlags flags() const {
JS_ASSERT(CurrentThreadCanReadCompilationData());
return flags_;
}
void addFlags(TypeObjectFlags flags) {
JS_ASSERT(CurrentThreadCanWriteCompilationData());
flags_ |= flags;
}
void clearFlags(TypeObjectFlags flags) {
JS_ASSERT(CurrentThreadCanWriteCompilationData());
flags_ &= ~flags;
}
bool hasNewScript() const {
JS_ASSERT(CurrentThreadCanReadCompilationData());
return addendum && addendum->isNewScript();
}
TypeNewScript *newScript() {
JS_ASSERT(CurrentThreadCanReadCompilationData());
return addendum->asNewScript();
}
bool hasTypedObject() {
JS_ASSERT(CurrentThreadCanReadCompilationData());
return addendum && addendum->isTypedObject();
}
TypeTypedObject *typedObject() {
JS_ASSERT(CurrentThreadCanReadCompilationData());
return addendum->asTypedObject();
}
void setAddendum(TypeObjectAddendum *addendum) {
JS_ASSERT(CurrentThreadCanWriteCompilationData());
this->addendum = addendum;
}
/*
* Tag the type object for a binary data type descriptor, instance,
* or handle with the type representation of the data it points at.
@ -919,6 +1003,7 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
TypeTypedObject::Kind kind ,
TypeRepresentation *repr);
private:
/*
* Properties of this object. This may contain JSID_VOID, representing the
* types of all integer indexes of the object, and/or JSID_EMPTY, holding
@ -953,6 +1038,7 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
* might update the property with a new type.
*/
Property **propertySet;
public:
/* If this is an interpreted function, the function object. */
HeapPtrFunction interpretedFunction;
@ -961,27 +1047,31 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
uint32_t padding;
#endif
inline TypeObject(const Class *clasp, TaggedProto proto, bool unknown);
inline TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags);
bool hasAnyFlags(TypeObjectFlags flags) {
JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
return !!(this->flags & flags);
return !!(this->flags() & flags);
}
bool hasAllFlags(TypeObjectFlags flags) {
JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
return (this->flags & flags) == flags;
return (this->flags() & flags) == flags;
}
bool unknownProperties() {
JS_ASSERT_IF(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES,
JS_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES,
hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES);
return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES);
}
bool shouldPreTenure() {
return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties();
}
bool hasTenuredProto() const {
return !(flags() & OBJECT_FLAG_NURSERY_PROTO);
}
gc::InitialHeap initialHeap(CompilerConstraintList *constraints);
bool canPreTenure() {
@ -991,7 +1081,7 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
// this bit reliably.
if (unknownProperties())
return false;
return (flags & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript();
return (flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript();
}
void setShouldPreTenure(ExclusiveContext *cx) {
@ -1046,12 +1136,20 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
static inline uint32_t offsetOfClasp() {
return offsetof(TypeObject, clasp_);
}
static inline uint32_t offsetOfProto() {
return offsetof(TypeObject, proto_);
}
private:
inline uint32_t basePropertyCount() const;
inline void setBasePropertyCount(uint32_t count);
static void staticAsserts() {
JS_STATIC_ASSERT(offsetof(TypeObject, proto) == offsetof(js::shadow::TypeObject, proto));
JS_STATIC_ASSERT(offsetof(TypeObject, proto_) == offsetof(js::shadow::TypeObject, proto));
}
};
@ -1247,6 +1345,7 @@ struct TypeObjectKey
const Class *clasp();
TaggedProto proto();
bool hasTenuredProto();
JSObject *singleton();
TypeNewScript *newScript();
@ -1416,7 +1515,7 @@ struct TypeCompartment
* js_ObjectClass).
*/
TypeObject *newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto,
bool unknown = false);
TypeObjectFlags initialFlags = 0);
/* Get or make an object for an allocation site, and add to the allocation site table. */
TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key);

Просмотреть файл

@ -25,61 +25,6 @@
#include "jsanalyzeinlines.h"
#include "jscntxtinlines.h"
inline bool
js::TaggedProto::isObject() const
{
/* Skip nullptr and Proxy::LazyProto. */
return uintptr_t(proto) > uintptr_t(Proxy::LazyProto);
}
inline bool
js::TaggedProto::isLazy() const
{
return proto == Proxy::LazyProto;
}
inline JSObject *
js::TaggedProto::toObject() const
{
JS_ASSERT(isObject());
return proto;
}
inline JSObject *
js::TaggedProto::toObjectOrNull() const
{
JS_ASSERT(!proto || isObject());
return proto;
}
template<class Outer>
inline bool
js::TaggedProtoOperations<Outer>::isLazy() const
{
return value()->isLazy();
}
template<class Outer>
inline bool
js::TaggedProtoOperations<Outer>::isObject() const
{
return value()->isObject();
}
template<class Outer>
inline JSObject *
js::TaggedProtoOperations<Outer>::toObject() const
{
return value()->toObject();
}
template<class Outer>
inline JSObject *
js::TaggedProtoOperations<Outer>::toObjectOrNull() const
{
return value()->toObjectOrNull();
}
namespace js {
namespace types {
@ -534,7 +479,7 @@ MarkTypeObjectUnknownProperties(JSContext *cx, TypeObject *obj,
if (cx->typeInferenceEnabled()) {
if (!obj->unknownProperties())
obj->markUnknown(cx);
if (markSetsUnknown && !(obj->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN))
if (markSetsUnknown && !(obj->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN))
cx->compartment()->types.markSetsUnknown(cx, obj);
}
}
@ -605,7 +550,8 @@ TypeScript::NumTypeSets(JSScript *script)
/* static */ inline StackTypeSet *
TypeScript::ThisTypes(JSScript *script)
{
return script->types->typeArray() + script->nTypeSets() + js::analyze::ThisSlot();
JS_ASSERT(CurrentThreadCanReadCompilationData());
return script->types->typeArray() + script->nTypeSets() + analyze::ThisSlot();
}
/*
@ -618,7 +564,8 @@ TypeScript::ThisTypes(JSScript *script)
TypeScript::ArgTypes(JSScript *script, unsigned i)
{
JS_ASSERT(i < script->function()->nargs());
return script->types->typeArray() + script->nTypeSets() + js::analyze::ArgSlot(i);
JS_ASSERT(CurrentThreadCanReadCompilationData());
return script->types->typeArray() + script->nTypeSets() + analyze::ArgSlot(i);
}
template <typename TYPESET>
@ -1089,10 +1036,8 @@ TypeSet::clearObjects()
}
bool
TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded)
TypeSet::addType(Type type, LifoAlloc *alloc)
{
JS_ASSERT_IF(padded, !*padded);
if (unknown())
return true;
@ -1100,8 +1045,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded)
flags |= TYPE_FLAG_BASE_MASK;
clearObjects();
JS_ASSERT(unknown());
if (padded)
*padded = true;
return true;
}
@ -1115,8 +1058,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded)
flag |= TYPE_FLAG_INT32;
flags |= flag;
if (padded)
*padded = true;
return true;
}
@ -1156,8 +1097,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded)
clearObjects();
}
if (padded)
*padded = true;
return true;
}
@ -1166,13 +1105,16 @@ ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type)
{
JS_ASSERT(cxArg->compartment()->activeAnalysis);
bool added = false;
if (!TypeSet::addType(type, &cxArg->typeLifoAlloc(), &added)) {
cxArg->compartment()->types.setPendingNukeTypes(cxArg);
if (hasType(type))
return;
{
AutoLockForCompilation lock(cxArg);
if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) {
cxArg->compartment()->types.setPendingNukeTypes(cxArg);
return;
}
}
if (!added)
return;
InferSpew(ISpewOps, "addType: %sT%p%s %s",
InferSpewColor(this), this, InferSpewColorReset(),
@ -1275,7 +1217,7 @@ TypeSet::getObjectClass(unsigned i) const
if (JSObject *object = getSingleObject(i))
return object->getClass();
if (TypeObject *object = getTypeObject(i))
return object->clasp;
return object->clasp();
return nullptr;
}
@ -1283,18 +1225,16 @@ TypeSet::getObjectClass(unsigned i) const
// TypeObject
/////////////////////////////////////////////////////////////////////
inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, bool unknown)
inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags)
{
mozilla::PodZero(this);
/* Inner objects may not appear on prototype chains. */
JS_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject);
this->clasp = clasp;
this->proto = proto.raw();
if (unknown)
flags |= OBJECT_FLAG_UNKNOWN_MASK;
this->clasp_ = clasp;
this->proto_ = proto.raw();
this->flags_ = initialFlags;
InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
}
@ -1302,15 +1242,17 @@ inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, bool unknow
inline uint32_t
TypeObject::basePropertyCount() const
{
return (flags & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
JS_ASSERT(CurrentThreadCanReadCompilationData());
return (flags() & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
}
inline void
TypeObject::setBasePropertyCount(uint32_t count)
{
// Note: Callers must ensure they are performing threadsafe operations.
JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
flags = (flags & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
| (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
flags_ = (flags() & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
| (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
}
inline HeapTypeSet *
@ -1322,36 +1264,46 @@ TypeObject::getProperty(ExclusiveContext *cx, jsid id)
JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
JS_ASSERT(!unknownProperties());
uint32_t propertyCount = basePropertyCount();
Property **pprop = HashSetInsert<jsid,Property,Property>
(cx->typeLifoAlloc(), propertySet, propertyCount, id);
if (!pprop) {
cx->compartment()->types.setPendingNukeTypes(cx);
return nullptr;
}
if (HeapTypeSet *types = maybeGetProperty(id))
return types;
uint32_t propertyCount;
Property **pprop;
{
AutoLockForCompilation lock(cx);
propertyCount = basePropertyCount();
pprop = HashSetInsert<jsid,Property,Property>
(cx->typeLifoAlloc(), propertySet, propertyCount, id);
if (!pprop) {
cx->compartment()->types.setPendingNukeTypes(cx);
return nullptr;
}
JS_ASSERT(!*pprop);
if (!*pprop) {
setBasePropertyCount(propertyCount);
if (!addProperty(cx, id, pprop)) {
setBasePropertyCount(0);
propertySet = nullptr;
return nullptr;
}
if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
markUnknown(cx);
}
/*
* Return an arbitrary property in the object, as all have unknown
* type and are treated as configured.
*/
unsigned count = getPropertyCount();
for (unsigned i = 0; i < count; i++) {
if (Property *prop = getProperty(i))
return &prop->types;
}
if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
markUnknown(cx);
MOZ_ASSUME_UNREACHABLE("Missing property");
/*
* Return an arbitrary property in the object, as all have unknown
* type and are treated as configured.
*/
unsigned count = getPropertyCount();
for (unsigned i = 0; i < count; i++) {
if (Property *prop = getProperty(i))
return &prop->types;
}
MOZ_ASSUME_UNREACHABLE("Missing property");
}
return &(*pprop)->types;
@ -1363,6 +1315,7 @@ TypeObject::maybeGetProperty(jsid id)
JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
JS_ASSERT(!unknownProperties());
JS_ASSERT(CurrentThreadCanReadCompilationData());
Property *prop = HashSetLookup<jsid,Property,Property>
(propertySet, basePropertyCount(), id);

Просмотреть файл

@ -1937,6 +1937,7 @@ GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
return false;
AutoLockForCompilation lock(cx);
global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
global->setConstructor(JSProto_GeneratorFunction, ObjectValue(*genFunction));
global->setPrototype(JSProto_GeneratorFunction, ObjectValue(*genFunctionProto));

Просмотреть файл

@ -1273,7 +1273,7 @@ NewObject(ExclusiveContext *cx, const Class *clasp, types::TypeObject *type_, JS
if (!NewObjectMetadata(cx, &metadata))
return nullptr;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(type->proto),
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, type->proto(),
parent, metadata, kind));
if (!shape)
return nullptr;
@ -1457,7 +1457,7 @@ js::NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc
NewObjectCache &cache = cx->runtime()->newObjectCache;
NewObjectCache::EntryIndex entry = -1;
if (parent == type->proto->getParent() &&
if (parent == type->proto().toObject()->getParent() &&
newKind == GenericObject &&
!cx->compartment()->hasObjectMetadataCallback())
{
@ -1985,9 +1985,12 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
* Swap the object's types, to restore their initial type information.
* The prototypes and classes of the objects were swapped in ReserveForTradeGuts.
*/
TypeObject *tmp = a->type_;
a->type_ = b->type_;
b->type_ = tmp;
{
AutoLockForCompilation lock(cx);
TypeObject *tmp = a->type_;
a->type_ = b->type_;
b->type_ = tmp;
}
/* Don't try to swap a JSFunction for a plain function JSObject. */
JS_ASSERT_IF(a->is<JSFunction>(), a->tenuredSizeOfThis() == b->tenuredSizeOfThis());
@ -2019,9 +2022,12 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
char tmp[mozilla::tl::Max<sizeof(JSFunction), sizeof(JSObject_Slots16)>::value];
JS_ASSERT(size <= sizeof(tmp));
js_memcpy(tmp, a, size);
js_memcpy(a, b, size);
js_memcpy(b, tmp, size);
{
AutoLockForCompilation lock(cx);
js_memcpy(tmp, a, size);
js_memcpy(a, b, size);
js_memcpy(b, tmp, size);
}
#ifdef JSGC_GENERATIONAL
/*
@ -2059,9 +2065,12 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
void *bpriv = b->hasPrivate() ? b->getPrivate() : nullptr;
char tmp[sizeof(JSObject)];
js_memcpy(&tmp, a, sizeof tmp);
js_memcpy(a, b, sizeof tmp);
js_memcpy(b, &tmp, sizeof tmp);
{
AutoLockForCompilation lock(cx);
js_memcpy(&tmp, a, sizeof tmp);
js_memcpy(a, b, sizeof tmp);
js_memcpy(b, &tmp, sizeof tmp);
}
if (a->isNative())
a->shape_->setNumFixedSlots(reserved.newafixed);
@ -2967,7 +2976,11 @@ js::SetClassAndProto(JSContext *cx, HandleObject obj,
MarkTypeObjectUnknownProperties(cx, obj->type(), true);
MarkTypeObjectUnknownProperties(cx, type, true);
obj->setType(type);
{
AutoLockForCompilation lock(cx);
obj->setType(type);
}
*succeeded = true;
return true;
}
@ -4030,7 +4043,7 @@ NativeGetInline(JSContext *cx,
case JSOP_GETPROP:
case JSOP_CALLPROP:
case JSOP_LENGTH:
script->baselineScript()->noteAccessedGetter(script->pcToOffset(pc));
script->baselineScript()->noteAccessedGetter(cx, script->pcToOffset(pc));
break;
default:
break;

Просмотреть файл

@ -474,7 +474,7 @@ class JSObject : public js::ObjectImpl
bool uninlinedIsProxy() const;
JSObject *getProto() const {
JS_ASSERT(!uninlinedIsProxy());
return js::ObjectImpl::getProto();
return getTaggedProto().toObjectOrNull();
}
static inline bool getProto(JSContext *cx, js::HandleObject obj,
js::MutableHandleObject protop);

Просмотреть файл

@ -393,6 +393,9 @@ JSObject::clearType(JSContext *cx, js::HandleObject obj)
inline void
JSObject::setType(js::types::TypeObject *newType)
{
// Note: This is usually called for newly created objects that haven't
// escaped to script yet, so don't require that the compilation lock be
// held here.
JS_ASSERT(newType);
JS_ASSERT(!hasSingletonType());
type_ = newType;
@ -405,7 +408,7 @@ JSObject::getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject
JS_ASSERT(obj->is<js::ProxyObject>());
return js::Proxy::getPrototypeOf(cx, obj, protop);
} else {
protop.set(obj->js::ObjectImpl::getProto());
protop.set(obj->getTaggedProto().toObjectOrNull());
return true;
}
}
@ -461,11 +464,11 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
* make sure their presence is consistent with the shape.
*/
JS_ASSERT(shape && type);
JS_ASSERT(type->clasp == shape->getObjectClass());
JS_ASSERT(type->clasp != &js::ArrayObject::class_);
JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp) == shape->numFixedSlots());
JS_ASSERT_IF(type->clasp->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind));
JS_ASSERT_IF(type->clasp->finalize, heap == js::gc::TenuredHeap);
JS_ASSERT(type->clasp() == shape->getObjectClass());
JS_ASSERT(type->clasp() != &js::ArrayObject::class_);
JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots());
JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind));
JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap);
JS_ASSERT_IF(extantSlots, dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan()));
js::HeapSlot *slots = extantSlots;
@ -495,7 +498,7 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
obj->slots = slots;
obj->elements = js::emptyObjectElements;
const js::Class *clasp = type->clasp;
const js::Class *clasp = type->clasp();
if (clasp->hasPrivate())
obj->privateRef(shape->numFixedSlots()) = nullptr;
@ -512,9 +515,9 @@ JSObject::createArray(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::
uint32_t length)
{
JS_ASSERT(shape && type);
JS_ASSERT(type->clasp == shape->getObjectClass());
JS_ASSERT(type->clasp == &js::ArrayObject::class_);
JS_ASSERT_IF(type->clasp->finalize, heap == js::gc::TenuredHeap);
JS_ASSERT(type->clasp() == shape->getObjectClass());
JS_ASSERT(type->clasp() == &js::ArrayObject::class_);
JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap);
/*
* Arrays use their fixed slots to store elements, and must have enough
@ -979,8 +982,11 @@ DefineConstructorAndPrototype(JSContext *cx, Handle<GlobalObject*> global,
JS_ASSERT(!global->nativeLookup(cx, id));
/* Set these first in case AddTypePropertyId looks for this class. */
global->setConstructor(key, ObjectValue(*ctor));
global->setPrototype(key, ObjectValue(*proto));
{
AutoLockForCompilation lock(cx);
global->setConstructor(key, ObjectValue(*ctor));
global->setPrototype(key, ObjectValue(*proto));
}
global->setConstructorPropertySlot(key, ObjectValue(*ctor));
if (!global->addDataProperty(cx, id, GlobalObject::constructorPropertySlot(key), 0)) {

Просмотреть файл

@ -2748,7 +2748,7 @@ Proxy::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHandl
return proxy->as<ProxyObject>().handler()->defaultValue(cx, proxy, hint, vp);
}
JSObject * const Proxy::LazyProto = reinterpret_cast<JSObject *>(0x1);
JSObject * const TaggedProto::LazyProto = reinterpret_cast<JSObject *>(0x1);
bool
Proxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject proto)

Просмотреть файл

@ -324,8 +324,6 @@ class Proxy
/* IC entry path for handling __noSuchMethod__ on access. */
static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,
MutableHandleValue vp);
static JSObject * const LazyProto;
};
// Use these in places where you don't want to #include vm/ProxyObject.h.

Просмотреть файл

@ -3015,7 +3015,10 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
JS_ASSERT(!script->isGenerator());
script->needsArgsObj_ = true;
{
AutoLockForCompilation lock(cx);
script->needsArgsObj_ = true;
}
#ifdef JS_ION
/*

Просмотреть файл

@ -977,7 +977,11 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
* that needsArgsObj is only called after the script has been analyzed.
*/
bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
bool needsArgsObj() const { JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; }
bool needsArgsObj() const {
JS_ASSERT(analyzedArgsUsage());
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
return needsArgsObj_;
}
void setNeedsArgsObj(bool needsArgsObj);
static bool argumentsOptimizationFailed(JSContext *cx, js::HandleScript script);
@ -1027,6 +1031,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
}
bool hasBaselineScript() const {
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
return baseline && baseline != BASELINE_DISABLED_SCRIPT;
}
bool canBaselineCompile() const {
@ -1036,7 +1041,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
JS_ASSERT(hasBaselineScript());
return baseline;
}
inline void setBaselineScript(js::jit::BaselineScript *baselineScript);
inline void setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript);
void updateBaselineOrIonRaw();

Просмотреть файл

@ -125,11 +125,14 @@ JSScript::setIsCallsiteClone(JSObject *fun) {
}
inline void
JSScript::setBaselineScript(js::jit::BaselineScript *baselineScript) {
JSScript::setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript) {
#ifdef JS_ION
if (hasBaselineScript())
js::jit::BaselineScript::writeBarrierPre(tenuredZone(), baseline);
#endif
mozilla::Maybe<js::AutoLockForCompilation> lock;
if (maybecx)
lock.construct(maybecx);
baseline = baselineScript;
updateBaselineOrIonRaw();
}

Просмотреть файл

@ -91,6 +91,8 @@ js::StartOffThreadIonCompile(JSContext *cx, jit::IonBuilder *builder)
if (!state.ionWorklist.append(builder))
return false;
cx->runtime()->addCompilationThread();
state.notifyAll(WorkerThreadState::PRODUCER);
return true;
}
@ -615,7 +617,7 @@ WorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *toke
iter.next())
{
types::TypeObject *object = iter.get<types::TypeObject>();
TaggedProto proto(object->proto);
TaggedProto proto(object->proto());
if (!proto.isObject())
continue;
@ -626,7 +628,9 @@ WorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *toke
JSObject *newProto = GetClassPrototypePure(&parseTask->scopeChain->global(), key);
JS_ASSERT(newProto);
object->proto = newProto;
// Note: this is safe to do without requiring the compilation lock, as
// the new type is not yet available to compilation threads.
object->setProtoUnchecked(newProto);
}
// Move the parsed script and all its contents into the desired compartment.
@ -760,7 +764,11 @@ WorkerThread::handleIonWorkload(WorkerThreadState &state)
jit::IonContext ictx(jit::CompileRuntime::get(runtime),
jit::CompileCompartment::get(ionBuilder->script()->compartment()),
&ionBuilder->alloc());
ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder));
AutoEnterIonCompilation ionCompiling;
bool succeeded = ionBuilder->build();
ionBuilder->clearForBackEnd();
if (succeeded)
ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder));
}
state.lock();

Просмотреть файл

@ -48,7 +48,7 @@ Wrapper::New(JSContext *cx, JSObject *obj, JSObject *parent, Wrapper *handler)
RootedValue priv(cx, ObjectValue(*obj));
ProxyOptions options;
options.setCallable(obj->isCallable());
return NewProxyObject(cx, handler, priv, Proxy::LazyProto, parent, options);
return NewProxyObject(cx, handler, priv, TaggedProto::LazyProto, parent, options);
}
JSObject *
@ -141,7 +141,7 @@ js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject
{
// Allow wrapping outer window proxies.
JS_ASSERT(!obj->is<WrapperObject>() || obj->getClass()->ext.innerObject);
JS_ASSERT(wrappedProto == Proxy::LazyProto);
JS_ASSERT(wrappedProto == TaggedProto::LazyProto);
return Wrapper::New(cx, obj, parent, &CrossCompartmentWrapper::singleton);
}

Просмотреть файл

@ -669,7 +669,7 @@ GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, Ha
RootedId shId(cx, AtomToId(selfHostedName));
RootedObject holder(cx, cx->global()->intrinsicsHolder());
if (HasDataProperty(cx, holder, shId, funVal.address()))
if (cx->global()->maybeGetIntrinsicValue(shId, funVal.address()))
return true;
if (!cx->runtime()->maybeWrappedSelfHostedFunction(cx, shId, funVal))
@ -685,5 +685,31 @@ GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, Ha
fun->setExtendedSlot(0, StringValue(selfHostedName));
funVal.setObject(*fun);
return JSObject::defineGeneric(cx, holder, shId, funVal, nullptr, nullptr, 0);
return cx->global()->addIntrinsicValue(cx, shId, funVal);
}
bool
GlobalObject::addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value)
{
RootedObject holder(cx, intrinsicsHolder());
// Work directly with the shape machinery underlying the object, so that we
// don't take the compilation lock until we are ready to update the object
// without triggering a GC.
uint32_t slot = holder->slotSpan();
RootedShape last(cx, holder->lastProperty());
Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
StackShape child(base, id, slot, holder->numFixedSlots(), 0, 0, 0);
RootedShape shape(cx, cx->compartment()->propertyTree.getChild(cx, last, holder->numFixedSlots(), child));
if (!shape)
return false;
AutoLockForCompilation lock(cx);
if (!JSObject::setLastProperty(cx, holder, shape))
return false;
holder->setSlot(shape->slot(), value);
return true;
}

Просмотреть файл

@ -513,26 +513,32 @@ class GlobalObject : public JSObject
return &getSlotRefForCompilation(INTRINSICS).toObject();
}
bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) {
bool maybeGetIntrinsicValue(jsid id, Value *vp) {
JS_ASSERT(CurrentThreadCanReadCompilationData());
JSObject *holder = intrinsicsHolder();
if (Shape *shape = holder->nativeLookupPure(name)) {
if (Shape *shape = holder->nativeLookupPure(id)) {
*vp = holder->getSlot(shape->slot());
return true;
}
return false;
}
bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) {
return maybeGetIntrinsicValue(NameToId(name), vp);
}
bool getIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue value) {
if (maybeGetIntrinsicValue(name, value.address()))
static bool getIntrinsicValue(JSContext *cx, Handle<GlobalObject*> global,
HandlePropertyName name, MutableHandleValue value)
{
if (global->maybeGetIntrinsicValue(name, value.address()))
return true;
Rooted<GlobalObject*> self(cx, this);
if (!cx->runtime()->cloneSelfHostedValue(cx, name, value))
return false;
RootedObject holder(cx, self->intrinsicsHolder());
RootedId id(cx, NameToId(name));
return JS_DefinePropertyById(cx, holder, id, value, nullptr, nullptr, 0);
return global->addIntrinsicValue(cx, id, value);
}
bool addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value);
bool setIntrinsicValue(JSContext *cx, PropertyName *name, HandleValue value) {
#ifdef DEBUG
RootedObject self(cx, this);

Просмотреть файл

@ -210,7 +210,7 @@ inline bool
GetIntrinsicOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue vp)
{
RootedPropertyName name(cx, cx->currentScript()->getName(pc));
return cx->global()->getIntrinsicValue(cx, name, vp);
return GlobalObject::getIntrinsicValue(cx, cx->global(), name, vp);
}
inline bool

Просмотреть файл

@ -1294,7 +1294,7 @@ SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, con
if ((uint32_t)i >= length) {
// Annotate script if provided with information (e.g. baseline)
if (script && script->hasBaselineScript() && *pc == JSOP_SETELEM)
script->baselineScript()->noteArrayWriteHole(script->pcToOffset(pc));
script->baselineScript()->noteArrayWriteHole(cx, script->pcToOffset(pc));
}
}
#endif

Просмотреть файл

@ -360,7 +360,7 @@ js::ObjectImpl::markChildren(JSTracer *trc)
MarkShape(trc, &shape_, "shape");
const Class *clasp = type_->clasp;
const Class *clasp = type_->clasp();
JSObject *obj = asObjectPtr();
if (clasp->trace)
clasp->trace(trc, obj);
@ -538,7 +538,7 @@ js::ArrayBufferDelegate(JSContext *cx, Handle<ObjectImpl*> obj)
if (obj->getPrivate())
return static_cast<JSObject *>(obj->getPrivate());
JSObject *delegate = NewObjectWithGivenProto(cx, &JSObject::class_,
obj->getProto(), nullptr);
obj->getTaggedProto(), nullptr);
obj->setPrivateGCThing(delegate);
return delegate;
}
@ -684,7 +684,7 @@ js::GetProperty(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> rece
/* No property? Recur or bottom out. */
if (desc.isUndefined()) {
current = current->getProto();
current = current->getTaggedProto().toObjectOrNull();
if (current)
continue;
@ -746,7 +746,7 @@ js::GetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> recei
/* No property? Recur or bottom out. */
if (desc.isUndefined()) {
current = current->getProto();
current = current->getTaggedProto().toObjectOrNull();
if (current)
continue;
@ -811,7 +811,7 @@ js::HasElement(JSContext *cx, Handle<ObjectImpl*> obj, uint32_t index, unsigned
return true;
}
current = current->getProto();
current = current->getTaggedProto().toObjectOrNull();
if (current)
continue;
@ -1009,7 +1009,7 @@ js::SetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> recei
MOZ_ASSUME_UNREACHABLE("NYI: setting PropertyOp-based property");
}
current = current->getProto();
current = current->getTaggedProto().toObjectOrNull();
if (current)
continue;

Просмотреть файл

@ -980,12 +980,14 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
/* These functions are public, and they should remain public. */
public:
JSObject * getProto() const {
return type_->proto;
js::TaggedProto getTaggedProto() const {
return type_->proto();
}
bool hasTenuredProto() const;
const Class *getClass() const {
return type_->clasp;
return type_->clasp();
}
static inline bool
@ -1172,10 +1174,6 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
*/
public:
js::TaggedProto getTaggedProto() const {
return TaggedProto(getProto());
}
Shape * lastProperty() const {
MOZ_ASSERT(shape_);
return shape_;

Просмотреть файл

@ -75,6 +75,9 @@ PerThreadData::PerThreadData(JSRuntime *runtime)
asmJSActivationStack_(nullptr),
dtoaState(nullptr),
suppressGC(0),
#ifdef DEBUG
ionCompiling(false),
#endif
activeCompilations(0)
{}
@ -135,6 +138,12 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
exclusiveAccessOwner(nullptr),
mainThreadHasExclusiveAccess(false),
numExclusiveThreads(0),
compilationLock(nullptr),
#ifdef DEBUG
compilationLockOwner(nullptr),
mainThreadHasCompilationLock(false),
#endif
numCompilationThreads(0),
#endif
systemZone(nullptr),
numCompartments(0),
@ -362,6 +371,10 @@ JSRuntime::init(uint32_t maxbytes)
exclusiveAccessLock = PR_NewLock();
if (!exclusiveAccessLock)
return false;
compilationLock = PR_NewLock();
if (!compilationLock)
return false;
#endif
if (!mainThread.init())
@ -483,6 +496,10 @@ JSRuntime::~JSRuntime()
// Avoid bogus asserts during teardown.
JS_ASSERT(!numExclusiveThreads);
mainThreadHasExclusiveAccess = true;
JS_ASSERT(!compilationLockOwner);
if (compilationLock)
PR_DestroyLock(compilationLock);
#endif
#ifdef JS_THREADSAFE
@ -736,6 +753,24 @@ JSRuntime::getDefaultLocale()
return defaultLocale;
}
void
JSRuntime::triggerActivityCallback(bool active)
{
if (!activityCallback)
return;
/*
* The activity callback must not trigger a GC: it would create a cirular
* dependency between entering a request and Rooted's requirement of being
* in a request. In practice this callback already cannot trigger GC. The
* suppression serves to inform the exact rooting hazard analysis of this
* property and ensures that it remains true in the future.
*/
AutoSuppressGC suppress(this);
activityCallback(activityCallbackArg, active);
}
void
JSRuntime::setGCMaxMallocBytes(size_t value)
{
@ -816,7 +851,7 @@ JSRuntime::activeGCInAtomsZone()
#if defined(DEBUG) && !defined(XP_WIN)
AutoProtectHeapForCompilation::AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
AutoProtectHeapForIonCompilation::AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: runtime(rt)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
@ -834,7 +869,7 @@ AutoProtectHeapForCompilation::AutoProtectHeapForCompilation(JSRuntime *rt MOZ_G
}
}
AutoProtectHeapForCompilation::~AutoProtectHeapForCompilation()
AutoProtectHeapForIonCompilation::~AutoProtectHeapForIonCompilation()
{
JS_ASSERT(runtime->heapProtected_);
JS_ASSERT(runtime->unprotectedArenas.empty());
@ -936,7 +971,7 @@ js::CurrentThreadCanAccessZone(Zone *zone)
return true;
}
#endif
#endif // JS_THREADSAFE
#ifdef DEBUG
@ -954,13 +989,73 @@ JSRuntime::assertCanLock(RuntimeLock which)
JS_ASSERT_IF(workerThreadState, !workerThreadState->isLocked());
case OperationCallbackLock:
JS_ASSERT(!currentThreadOwnsOperationCallbackLock());
case CompilationLock:
JS_ASSERT(compilationLockOwner != PR_GetCurrentThread());
case GCLock:
JS_ASSERT(gcLockOwner != PR_GetCurrentThread());
break;
default:
MOZ_CRASH();
}
#endif // JS_THREADSAFE
#endif // JS_WORKER_THREADS
}
AutoEnterIonCompilation::AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
#ifdef JS_WORKER_THREADS
PerThreadData *pt = js::TlsPerThreadData.get();
JS_ASSERT(!pt->ionCompiling);
pt->ionCompiling = true;
#endif
}
AutoEnterIonCompilation::~AutoEnterIonCompilation()
{
#ifdef JS_WORKER_THREADS
PerThreadData *pt = js::TlsPerThreadData.get();
JS_ASSERT(pt->ionCompiling);
pt->ionCompiling = false;
#endif
}
bool
js::CurrentThreadCanWriteCompilationData()
{
#ifdef JS_WORKER_THREADS
PerThreadData *pt = TlsPerThreadData.get();
// Data can only be read from during compilation.
if (pt->ionCompiling)
return false;
// Ignore what threads with exclusive contexts are doing; these never have
// run scripts or have associated compilation threads.
JSRuntime *rt = pt->runtimeIfOnOwnerThread();
if (!rt)
return true;
return rt->currentThreadHasCompilationLock();
#else
return true;
#endif
}
bool
js::CurrentThreadCanReadCompilationData()
{
#ifdef JS_WORKER_THREADS
PerThreadData *pt = TlsPerThreadData.get();
// Data can always be read from freely outside of compilation.
if (!pt || !pt->ionCompiling)
return true;
return pt->runtime_->currentThreadHasCompilationLock();
#else
return true;
#endif
}
#endif // DEBUG

Просмотреть файл

@ -535,6 +535,9 @@ class PerThreadData : public PerThreadDataFriendFields,
friend class js::ActivationIterator;
friend class js::jit::JitActivation;
friend class js::AsmJSActivation;
#ifdef DEBUG
friend bool js::CurrentThreadCanReadCompilationData();
#endif
/*
* Points to the most recent activation running on the thread.
@ -577,7 +580,12 @@ class PerThreadData : public PerThreadDataFriendFields,
*/
int32_t suppressGC;
// Whether there is an active compilation on this thread.
#ifdef DEBUG
// Whether this thread is actively Ion compiling.
bool ionCompiling;
#endif
// Number of active bytecode compilation on this thread.
unsigned activeCompilations;
PerThreadData(JSRuntime *runtime);
@ -677,7 +685,8 @@ class MarkingValidator;
typedef Vector<JS::Zone *, 4, SystemAllocPolicy> ZoneVector;
class AutoLockForExclusiveAccess;
class AutoProtectHeapForCompilation;
class AutoLockForCompilation;
class AutoProtectHeapForIonCompilation;
void RecomputeStackLimit(JSRuntime *rt, StackKind kind);
@ -727,6 +736,7 @@ struct JSRuntime : public JS::shadow::Runtime,
ExclusiveAccessLock,
WorkerThreadStateLock,
OperationCallbackLock,
CompilationLock,
GCLock
};
#ifdef DEBUG
@ -805,20 +815,44 @@ struct JSRuntime : public JS::shadow::Runtime,
friend class js::AutoLockForExclusiveAccess;
/*
* Lock taken when using data that can be modified by the main thread but
* read by Ion compilation threads. Any time either the main thread writes
* such data or the compilation thread reads it, this lock must be taken.
* Note that no externally visible data is modified by the compilation
* thread, so the main thread never needs to take this lock when reading.
*/
PRLock *compilationLock;
#ifdef DEBUG
PRThread *compilationLockOwner;
bool mainThreadHasCompilationLock;
#endif
/* Number of in flight Ion compilations. */
size_t numCompilationThreads;
friend class js::AutoLockForCompilation;
#ifdef DEBUG
friend bool js::CurrentThreadCanWriteCompilationData();
friend bool js::CurrentThreadCanReadCompilationData();
#endif
public:
void setUsedByExclusiveThread(JS::Zone *zone);
void clearUsedByExclusiveThread(JS::Zone *zone);
#endif // JS_THREADSAFE && JS_ION
#ifdef DEBUG
bool currentThreadHasExclusiveAccess() {
#if defined(JS_WORKER_THREADS) && defined(DEBUG)
#ifdef JS_WORKER_THREADS
return (!numExclusiveThreads && mainThreadHasExclusiveAccess) ||
exclusiveAccessOwner == PR_GetCurrentThread();
exclusiveAccessOwner == PR_GetCurrentThread();
#else
return true;
#endif
}
#endif // DEBUG
bool exclusiveThreadsPresent() const {
#ifdef JS_WORKER_THREADS
@ -828,6 +862,33 @@ struct JSRuntime : public JS::shadow::Runtime,
#endif
}
void addCompilationThread() {
numCompilationThreads++;
}
void removeCompilationThread() {
JS_ASSERT(numCompilationThreads);
numCompilationThreads--;
}
bool compilationThreadsPresent() const {
#ifdef JS_WORKER_THREADS
return numCompilationThreads > 0;
#else
return false;
#endif
}
#ifdef DEBUG
bool currentThreadHasCompilationLock() {
#ifdef JS_WORKER_THREADS
return (!numCompilationThreads && mainThreadHasCompilationLock) ||
compilationLockOwner == PR_GetCurrentThread();
#else
return true;
#endif
}
#endif // DEBUG
/* Embedders can use this zone however they wish. */
JS::Zone *systemZone;
@ -972,6 +1033,7 @@ struct JSRuntime : public JS::shadow::Runtime,
js::ActivityCallback activityCallback;
void *activityCallbackArg;
void triggerActivityCallback(bool active);
#ifdef JS_THREADSAFE
/* The request depth for this thread. */
@ -1431,7 +1493,7 @@ struct JSRuntime : public JS::shadow::Runtime,
const char *numGrouping;
#endif
friend class js::AutoProtectHeapForCompilation;
friend class js::AutoProtectHeapForIonCompilation;
friend class js::AutoThreadSafeAccess;
mozilla::DebugOnly<bool> heapProtected_;
#ifdef DEBUG
@ -2049,16 +2111,36 @@ class RuntimeAllocPolicy
extern const JSSecurityCallbacks NullSecurityCallbacks;
class AutoProtectHeapForCompilation
// Debugging RAII class which marks the current thread as performing an Ion
// compilation, for use by CurrentThreadCan{Read,Write}CompilationData
class AutoEnterIonCompilation
{
public:
#ifdef DEBUG
AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
~AutoEnterIonCompilation();
#else
AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
#endif
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
// Debugging RAII class which protects the entire GC heap for the duration of an
// Ion compilation. When used only the main thread will be active and all
// accesses to GC things must be wrapped by an AutoThreadSafeAccess instance.
class AutoProtectHeapForIonCompilation
{
public:
#if defined(DEBUG) && !defined(XP_WIN)
JSRuntime *runtime;
AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
~AutoProtectHeapForCompilation();
AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
~AutoProtectHeapForIonCompilation();
#else
AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}

Просмотреть файл

@ -56,13 +56,14 @@ SPSProfiler::enable(bool enabled)
if (enabled_ == enabled)
return;
enabled_ = enabled;
/*
* Ensure all future generated code will be instrumented, or that all
* currently instrumented code is discarded
*/
ReleaseAllJITCode(rt->defaultFreeOp());
enabled_ = enabled;
#ifdef JS_ION
/* Toggle SPS-related jumps on baseline jitcode.
* The call to |ReleaseAllJITCode| above will release most baseline jitcode, but not

Просмотреть файл

@ -958,10 +958,11 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, Handle<PropertyName*> na
JSScript *cscript = CloneScript(cx, NullPtr(), targetFun, sourceScript);
if (!cscript)
return false;
targetFun->setScript(cscript);
cscript->setFunction(targetFun);
JS_ASSERT(sourceFun->nargs() == targetFun->nargs());
targetFun->setFlags(sourceFun->flags() | JSFunction::EXTENDED);
targetFun->setScript(cscript);
return true;
}
@ -1010,7 +1011,7 @@ JSFunction *
js::SelfHostedFunction(JSContext *cx, HandlePropertyName propName)
{
RootedValue func(cx);
if (!cx->global()->getIntrinsicValue(cx, propName, &func))
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), propName, &func))
return nullptr;
JS_ASSERT(func.isObject());

Просмотреть файл

@ -338,7 +338,7 @@ ArrayBufferObject::neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer)
size_t numViews = 0;
for (view = GetViewList(buffer); view; view = view->nextView()) {
numViews++;
view->neuter();
view->neuter(cx);
// Notify compiled jit code that the base pointer has moved.
MarkObjectStateChange(cx, view);
@ -1182,8 +1182,10 @@ TypedArrayObject::isArrayIndex(jsid id, uint32_t *ip)
}
void
TypedArrayObject::neuter()
TypedArrayObject::neuter(JSContext *cx)
{
AutoLockForCompilation lock(cx);
setSlot(LENGTH_SLOT, Int32Value(0));
setSlot(BYTELENGTH_SLOT, Int32Value(0));
setSlot(BYTEOFFSET_SLOT, Int32Value(0));
@ -2625,12 +2627,12 @@ ArrayBufferViewObject::prependToViews(ArrayBufferViewObject *viewsHead)
}
void
ArrayBufferViewObject::neuter()
ArrayBufferViewObject::neuter(JSContext *cx)
{
if (is<DataViewObject>())
as<DataViewObject>().neuter();
else
as<TypedArrayObject>().neuter();
as<TypedArrayObject>().neuter(cx);
}
// this default implementation is only valid for integer types

Просмотреть файл

@ -276,7 +276,7 @@ class ArrayBufferViewObject : public JSObject
void prependToViews(ArrayBufferViewObject *viewsHead);
void neuter();
void neuter(JSContext *cx);
static void trace(JSTracer *trc, JSObject *obj);
};
@ -353,7 +353,7 @@ class TypedArrayObject : public ArrayBufferViewObject
inline bool isArrayIndex(jsid id, uint32_t *ip = nullptr);
void copyTypedArrayElement(uint32_t index, MutableHandleValue vp);
void neuter();
void neuter(JSContext *cx);
static uint32_t slotWidth(int atype) {
switch (atype) {

Просмотреть файл

@ -53,6 +53,8 @@ EXTRA_DSO_LDOPTS += \
-lutils \
-L$(DEPTH)/media/omx-plugin/lib/ics/libstagefright \
-lstagefright \
-L$(DEPTH)/media/omx-plugin/lib/ics/libvideoeditorplayer \
-lvideoeditorplayer \
$(NULL)
INCLUDES += \

Просмотреть файл

@ -37,6 +37,14 @@
#define MOZ_ANDROID_V2_X_X
#endif
#if !defined(MOZ_ANDROID_V2_X_X) && !defined(MOZ_ANDROID_HC)
#define MOZ_ANDROID_V4_OR_ABOVE
#endif
#if defined(MOZ_ANDROID_V4_OR_ABOVE)
#include <I420ColorConverter.h>
#endif
using namespace MPAPI;
#if !defined(MOZ_STAGEFRIGHT_OFF_T)
@ -68,6 +76,8 @@ class OmxDecoder {
int32_t mVideoSliceHeight;
int32_t mVideoCropLeft;
int32_t mVideoCropTop;
int32_t mVideoCropRight;
int32_t mVideoCropBottom;
int32_t mVideoRotation;
int32_t mAudioChannels;
int32_t mAudioSampleRate;
@ -92,6 +102,7 @@ class OmxDecoder {
void ToVideoFrame_YVU420PackedSemiPlanar32m4ka(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame);
bool ToVideoFrame_RGB565(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback);
bool ToVideoFrame_ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback);
bool ToVideoFrame_I420ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback);
bool ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback);
bool ToAudioFrame(AudioFrame *aFrame, int64_t aTimeUs, void *aData, size_t aDataOffset, size_t aSize,
int32_t aAudioChannels, int32_t aAudioSampleRate);
@ -139,6 +150,8 @@ OmxDecoder::OmxDecoder(PluginHost *aPluginHost, Decoder *aDecoder) :
mVideoSliceHeight(0),
mVideoCropLeft(0),
mVideoCropTop(0),
mVideoCropRight(0),
mVideoCropBottom(0),
mVideoRotation(0),
mAudioChannels(-1),
mAudioSampleRate(-1),
@ -226,11 +239,48 @@ static uint32_t GetVideoCreationFlags(PluginHost* aPluginHost)
#endif
}
static bool
IsColorFormatSupported(OMX_COLOR_FORMATTYPE aColorFormat)
{
switch (aColorFormat) {
case OMX_COLOR_FormatCbYCrY:
case OMX_COLOR_FormatYUV420Planar:
case OMX_COLOR_FormatYUV420SemiPlanar:
case OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka:
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
LOG("Colour format %#x supported natively.", aColorFormat);
return true;
default:
break;
}
#if !defined(MOZ_ANDROID_HC)
if (ColorConverter(aColorFormat, OMX_COLOR_Format16bitRGB565).isValid()) {
LOG("Colour format %#x supported by Android ColorConverter.", aColorFormat);
return true;
}
#endif
#if defined(MOZ_ANDROID_V4_OR_ABOVE)
I420ColorConverter yuvConverter;
if (yuvConverter.isLoaded() &&
yuvConverter.getDecoderOutputFormat() == aColorFormat) {
LOG("Colour format %#x supported by Android I420ColorConverter.", aColorFormat);
return true;
}
#endif
return false;
}
static sp<MediaSource> CreateVideoSource(PluginHost* aPluginHost,
const sp<IOMX>& aOmx,
const sp<MediaSource>& aVideoTrack)
{
uint32_t flags = GetVideoCreationFlags(aPluginHost);
if (flags == DEFAULT_STAGEFRIGHT_FLAGS) {
// Let Stagefright choose hardware or software decoder.
sp<MediaSource> videoSource = OMXCodec::Create(aOmx, aVideoTrack->getFormat(),
@ -242,30 +292,14 @@ static sp<MediaSource> CreateVideoSource(PluginHost* aPluginHost,
// check whether we know how to decode this video.
int32_t videoColorFormat;
if (videoSource->getFormat()->findInt32(kKeyColorFormat, &videoColorFormat)) {
switch (videoColorFormat) {
// We know how to convert these color formats.
case OMX_COLOR_FormatCbYCrY:
case OMX_COLOR_FormatYUV420Planar:
case OMX_COLOR_FormatYUV420SemiPlanar:
case OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka:
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
// Use the decoder Stagefright chose for us!
return videoSource;
// Use software decoder for color formats we don't know how to convert.
default:
#ifndef MOZ_ANDROID_HC
if (ColorConverter((OMX_COLOR_FORMATTYPE)videoColorFormat,
OMX_COLOR_Format16bitRGB565).isValid()) {
return videoSource;
}
#endif
// We need to implement a ToVideoFrame_*() color conversion
// function for this video color format.
LOG("Unknown video color format: %#x", videoColorFormat);
break;
if (IsColorFormatSupported((OMX_COLOR_FORMATTYPE)videoColorFormat)) {
return videoSource;
}
// We need to implement a ToVideoFrame_*() color conversion
// function for this video color format.
LOG("Unknown video color format: %#x", videoColorFormat);
} else {
LOG("Video color format not found");
}
@ -472,29 +506,28 @@ bool OmxDecoder::SetVideoFormat() {
return false;
}
int32_t cropRight, cropBottom;
// Gingerbread does not support the kKeyCropRect key
#if !defined(MOZ_ANDROID_V2_X_X)
if (!format->findRect(kKeyCropRect, &mVideoCropLeft, &mVideoCropTop,
&cropRight, &cropBottom)) {
&mVideoCropRight, &mVideoCropBottom)) {
#endif
mVideoCropLeft = 0;
mVideoCropTop = 0;
cropRight = mVideoStride - 1;
cropBottom = mVideoSliceHeight - 1;
mVideoCropRight = mVideoStride - 1;
mVideoCropBottom = mVideoSliceHeight - 1;
LOG("crop rect not available, assuming no cropping");
#if !defined(MOZ_ANDROID_V2_X_X)
}
#endif
if (mVideoCropLeft < 0 || mVideoCropLeft >= cropRight || cropRight >= mVideoStride ||
mVideoCropTop < 0 || mVideoCropTop >= cropBottom || cropBottom >= mVideoSliceHeight) {
LOG("invalid crop rect %d,%d-%d,%d", mVideoCropLeft, mVideoCropTop, cropRight, cropBottom);
if (mVideoCropLeft < 0 || mVideoCropLeft >= mVideoCropRight || mVideoCropRight >= mVideoStride ||
mVideoCropTop < 0 || mVideoCropTop >= mVideoCropBottom || mVideoCropBottom >= mVideoSliceHeight) {
LOG("invalid crop rect %d,%d-%d,%d", mVideoCropLeft, mVideoCropTop, mVideoCropRight, mVideoCropBottom);
return false;
}
mVideoWidth = cropRight - mVideoCropLeft + 1;
mVideoHeight = cropBottom - mVideoCropTop + 1;
mVideoWidth = mVideoCropRight - mVideoCropLeft + 1;
mVideoHeight = mVideoCropBottom - mVideoCropTop + 1;
MOZ_ASSERT(mVideoWidth > 0 && mVideoWidth <= mVideoStride);
MOZ_ASSERT(mVideoHeight > 0 && mVideoHeight <= mVideoSliceHeight);
@ -515,7 +548,7 @@ bool OmxDecoder::SetVideoFormat() {
LOG("width: %d height: %d component: %s format: %#x stride: %d sliceHeight: %d rotation: %d crop: %d,%d-%d,%d",
mVideoWidth, mVideoHeight, componentName, mVideoColorFormat,
mVideoStride, mVideoSliceHeight, mVideoRotation,
mVideoCropLeft, mVideoCropTop, cropRight, cropBottom);
mVideoCropLeft, mVideoCropTop, mVideoCropRight, mVideoCropBottom);
return true;
}
@ -682,6 +715,40 @@ bool OmxDecoder::ToVideoFrame_ColorConverter(VideoFrame *aFrame, int64_t aTimeUs
#endif
}
bool OmxDecoder::ToVideoFrame_I420ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback)
{
#if defined(MOZ_ANDROID_V4_OR_ABOVE)
I420ColorConverter yuvConverter;
if (!yuvConverter.isLoaded()) {
return false;
}
if (yuvConverter.getDecoderOutputFormat() != mVideoColorFormat) {
return false;
}
void *buffer = (*aBufferCallback)(mVideoWidth, mVideoHeight, MPAPI::I420);
ARect crop = { mVideoCropLeft, mVideoCropTop, mVideoCropRight, mVideoCropBottom };
int result = yuvConverter.convertDecoderOutputToI420(aData,
mVideoWidth,
mVideoHeight,
crop,
buffer);
// result is 0 on success, -1 otherwise.
if (result == OK) {
aFrame->mTimeUs = aTimeUs;
aFrame->mSize = mVideoWidth * mVideoHeight * 3 / 2;
}
return result == OK;
#else
return false;
#endif
}
bool OmxDecoder::ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback) {
switch (mVideoColorFormat) {
// Froyo support is best handled with the android color conversion code. I
@ -710,7 +777,8 @@ bool OmxDecoder::ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData,
break;
#endif
default:
if (!ToVideoFrame_ColorConverter(aFrame, aTimeUs, aData, aSize, aKeyFrame, aBufferCallback)) {
if (!ToVideoFrame_ColorConverter(aFrame, aTimeUs, aData, aSize, aKeyFrame, aBufferCallback) &&
!ToVideoFrame_I420ColorConverter(aFrame, aTimeUs, aData, aSize, aKeyFrame, aBufferCallback)) {
LOG("Unknown video color format: %#x", mVideoColorFormat);
return false;
}

Просмотреть файл

@ -0,0 +1,35 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef I420_COLOR_CONVERTER_H
#define I420_COLOR_CONVERTER_H
#include <II420ColorConverter.h>
// This is a wrapper around the I420 color converter functions in
// II420ColorConverter, which is loaded from a shared library.
class I420ColorConverter: public II420ColorConverter {
public:
I420ColorConverter();
~I420ColorConverter();
// Returns true if the converter functions are successfully loaded.
bool isLoaded();
private:
void* mHandle;
};
#endif /* I420_COLOR_CONVERTER_H */

Просмотреть файл

@ -0,0 +1,127 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef II420_COLOR_CONVERTER_H
#define II420_COLOR_CONVERTER_H
#include <stdint.h>
#include <android/rect.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct II420ColorConverter {
/*
* getDecoderOutputFormat
* Returns the color format (OMX_COLOR_FORMATTYPE) of the decoder output.
* If it is I420 (OMX_COLOR_FormatYUV420Planar), no conversion is needed,
* and convertDecoderOutputToI420() can be a no-op.
*/
int (*getDecoderOutputFormat)();
/*
* convertDecoderOutputToI420
* @Desc Converts from the decoder output format to I420 format.
* @note Caller (e.g. VideoEditor) owns the buffers
* @param decoderBits (IN) Pointer to the buffer contains decoder output
* @param decoderWidth (IN) Buffer width, as reported by the decoder
* metadata (kKeyWidth)
* @param decoderHeight (IN) Buffer height, as reported by the decoder
* metadata (kKeyHeight)
* @param decoderRect (IN) The rectangle of the actual frame, as
* reported by decoder metadata (kKeyCropRect)
* @param dstBits (OUT) Pointer to the output I420 buffer
* @return -1 Any error
* @return 0 No Error
*/
int (*convertDecoderOutputToI420)(
void* decoderBits, int decoderWidth, int decoderHeight,
ARect decoderRect, void* dstBits);
/*
* getEncoderIntputFormat
* Returns the color format (OMX_COLOR_FORMATTYPE) of the encoder input.
* If it is I420 (OMX_COLOR_FormatYUV420Planar), no conversion is needed,
* and convertI420ToEncoderInput() and getEncoderInputBufferInfo() can
* be no-ops.
*/
int (*getEncoderInputFormat)();
/* convertI420ToEncoderInput
* @Desc This function converts from I420 to the encoder input format
* @note Caller (e.g. VideoEditor) owns the buffers
* @param srcBits (IN) Pointer to the input I420 buffer
* @param srcWidth (IN) Width of the I420 frame
* @param srcHeight (IN) Height of the I420 frame
* @param encoderWidth (IN) Encoder buffer width, as calculated by
* getEncoderBufferInfo()
* @param encoderHeight (IN) Encoder buffer height, as calculated by
* getEncoderBufferInfo()
* @param encoderRect (IN) Rect coordinates of the actual frame inside
* the encoder buffer, as calculated by
* getEncoderBufferInfo().
* @param encoderBits (OUT) Pointer to the output buffer. The size of
* this buffer is calculated by
* getEncoderBufferInfo()
* @return -1 Any error
* @return 0 No Error
*/
int (*convertI420ToEncoderInput)(
void* srcBits, int srcWidth, int srcHeight,
int encoderWidth, int encoderHeight, ARect encoderRect,
void* encoderBits);
/* getEncoderInputBufferInfo
* @Desc This function returns metadata for the encoder input buffer
* based on the actual I420 frame width and height.
* @note This API should be be used to obtain the necessary information
* before calling convertI420ToEncoderInput().
* VideoEditor knows only the width and height of the I420 buffer,
* but it also needs know the width, height, and size of the
* encoder input buffer. The encoder input buffer width and height
* are used to set the metadata for the encoder.
* @param srcWidth (IN) Width of the I420 frame
* @param srcHeight (IN) Height of the I420 frame
* @param encoderWidth (OUT) Encoder buffer width needed
* @param encoderHeight (OUT) Encoder buffer height needed
* @param encoderRect (OUT) Rect coordinates of the actual frame inside
* the encoder buffer
* @param encoderBufferSize (OUT) The size of the buffer that need to be
* allocated by the caller before invoking
* convertI420ToEncoderInput().
* @return -1 Any error
* @return 0 No Error
*/
int (*getEncoderInputBufferInfo)(
int srcWidth, int srcHeight,
int* encoderWidth, int* encoderHeight,
ARect* encoderRect, int* encoderBufferSize);
} II420ColorConverter;
/* The only function that the shared library needs to expose: It fills the
function pointers in II420ColorConverter */
void getI420ColorConverter(II420ColorConverter *converter);
#if defined(__cplusplus)
}
#endif
#endif // II420_COLOR_CONVERTER_H

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше