This commit is contained in:
Brad Lassey 2011-10-25 10:54:54 -04:00
Родитель 8550465d4f 4c7bd5e1ab
Коммит 7e6de06af3
131 изменённых файлов: 1699 добавлений и 2427 удалений

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

@ -43,7 +43,7 @@
#include <time.h>
#include <windows.h>
#include <pstore.h>
#include <ole2.h>
#include "nsIBrowserProfileMigrator.h"
#include "nsIObserverService.h"
#include "nsTArray.h"
@ -61,6 +61,79 @@ struct SignonData {
char* realm;
};
// VC11 doesn't ship with pstore.h, so we go ahead and define the stuff that
// we need from that file here.
class IEnumPStoreItems : public IUnknown {
public:
virtual HRESULT STDMETHODCALLTYPE Next(DWORD celt, LPWSTR* rgelt,
DWORD* pceltFetched) = 0;
virtual HRESULT STDMETHODCALLTYPE Skip(DWORD celt) = 0;
virtual HRESULT STDMETHODCALLTYPE Reset() = 0;
virtual HRESULT STDMETHODCALLTYPE Clone(IEnumPStoreItems** ppenum) = 0;
};
class IEnumPStoreTypes; // not used
struct PST_PROVIDERINFO; // not used
struct PST_TYPEINFO; // not used
struct PST_PROMPTINFO; // not used
struct PST_ACCESSRULESET; // not used
typedef DWORD PST_KEY;
typedef DWORD PST_ACCESSMODE;
class IPStore : public IUnknown {
public:
virtual HRESULT STDMETHODCALLTYPE GetInfo(PST_PROVIDERINFO** ppProperties) = 0;
virtual HRESULT STDMETHODCALLTYPE GetProvParam(DWORD dwParam, DWORD* pcbData,
BYTE** ppbData, DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE SetProvParam(DWORD dwParam, DWORD cbData,
BYTE* pbData, DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateType(PST_KEY Key, const GUID* pType,
PST_TYPEINFO* pInfo, DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(PST_KEY Key, const GUID* pType,
PST_TYPEINFO** ppInfo, DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE DeleteType(PST_KEY Key, const GUID* pType,
DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateSubtype(PST_KEY Key, const GUID* pType,
const GUID* pSubtype, PST_TYPEINFO* pInfo,
PST_ACCESSRULESET* pRules, DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSubtypeInfo(PST_KEY Key, const GUID* pType,
const GUID* pSubtype, PST_TYPEINFO** ppInfo,
DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE DeleteSubtype(PST_KEY Key, const GUID* pType,
const GUID* pSubtype, DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE ReadAccessRuleset(PST_KEY Key, const GUID* pType,
const GUID* pSubtype, PST_ACCESSRULESET** ppRules,
DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE WriteAccessRuleset(PST_KEY Key, const GUID* pType,
const GUID* pSubtype, PST_ACCESSRULESET* pRules,
DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE EnumTypes(PST_KEY Key, DWORD dwFlags, IEnumPStoreTypes** ppenum) = 0;
virtual HRESULT STDMETHODCALLTYPE EnumSubtypes(PST_KEY Key, const GUID* pType,
DWORD dwFlags, IEnumPStoreTypes** ppenum) = 0;
virtual HRESULT STDMETHODCALLTYPE DeleteItem(PST_KEY Key, const GUID* pItemType,
const GUID* pItemSubtype, LPCWSTR szItemName,
PST_PROMPTINFO* pPromptInfo, DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE ReadItem(PST_KEY Key, const GUID* pItemType,
const GUID* pItemSubtype, LPCWSTR szItemName,
DWORD* pcbData, BYTE** ppbData,
PST_PROMPTINFO* pPromptInfo, DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE WriteItem(PST_KEY Key, const GUID* pItemType,
const GUID* pItemSubtype, LPCWSTR szItemName,
DWORD cbData, BYTE* pbData,
PST_PROMPTINFO* pPromptInfo, DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE OpenItem(PST_KEY Key, const GUID* pItemType,
const GUID* pItemSubtype, LPCWSTR szItemName,
PST_ACCESSMODE ModeFlags, PST_PROMPTINFO* pPromptInfo,
DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE CloseItem(PST_KEY Key, const GUID* pItemType,
const GUID* pItemSubtype, LPCWSTR szItemName,
DWORD dwFlags) = 0;
virtual HRESULT STDMETHODCALLTYPE EnumItems(PST_KEY Key, const GUID* pItemType,
const GUID* pItemSubtype, DWORD dwFlags,
IEnumPStoreItems** ppenum) = 0;
};
class nsIEProfileMigrator : public nsIBrowserProfileMigrator,
public nsINavHistoryBatchCallback {
public:

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

@ -84,16 +84,18 @@ function test() {
let curState = JSON.parse(ss.getBrowserState());
for (let i = 0; i < curState.windows[0].tabs.length; i++) {
if (state.windows[0].tabs[i].extData) {
is(curState.windows[0].tabs[i].extData["uniq"],
state.windows[0].tabs[i].extData["uniq"],
let tabState = state.windows[0].tabs[i];
let tabCurState = curState.windows[0].tabs[i];
if (tabState.extData) {
is(tabCurState.extData["uniq"], tabState.extData["uniq"],
"sanity check that tab has correct extData");
}
else {
ok(!("extData" in curState.windows[0].tabs[i]),
"sanity check that tab doesn't have extData");
//XXXzpao output the tab state to help debug bug 679590
info("tabState: " + JSON.stringify(curState.windows[0].tabs[i]));
// We aren't expecting there to be any data on extData, but panorama
// may be setting something, so we need to make sure that if we do have
// data, we just don't have anything for "uniq".
ok(!("extData" in tabCurState) || !("uniq" in tabCurState.extData),
"sanity check that tab doesn't have extData or extData doesn't have 'uniq'");
}
}

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

@ -372,7 +372,10 @@ nsDOMBlobBuilder::Append(const jsval& aData, JSContext* aCx)
// Is it an object?
if (JSVAL_IS_OBJECT(aData)) {
JSObject* obj = JSVAL_TO_OBJECT(aData);
NS_ASSERTION(obj, "Er, what?");
if (!obj) {
// We got passed null. Just do nothing.
return NS_OK;
}
// Is it a Blob?
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(

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

@ -37,6 +37,9 @@ ok(false, "NOT REACHED");
ok(true, "an empty argument to append should throw");
}
blobBuilder.append(null);
// Yay we didn't crash.
blobBuilder.append("squiggle");
let blob1 = blobBuilder.getBlob();
ok(blob1 instanceof Blob, "getBlob should produce Blobs");

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

@ -95,21 +95,6 @@ SVGPathSegListSMILType::IsEqual(const nsSMILValue& aLeft,
*static_cast<const SVGPathDataAndOwner*>(aRight.mU.mPtr);
}
static bool
ArcFlagsDiffer(SVGPathDataAndOwner::const_iterator aPathData1,
SVGPathDataAndOwner::const_iterator aPathData2)
{
NS_ABORT_IF_FALSE
(SVGPathSegUtils::IsArcType(SVGPathSegUtils::DecodeType(aPathData1[0])),
"ArcFlagsDiffer called with non-arc segment");
NS_ABORT_IF_FALSE
(SVGPathSegUtils::IsArcType(SVGPathSegUtils::DecodeType(aPathData2[0])),
"ArcFlagsDiffer called with non-arc segment");
return aPathData1[LARGE_ARC_FLAG_IDX] != aPathData2[LARGE_ARC_FLAG_IDX] ||
aPathData1[SWEEP_FLAG_IDX] != aPathData2[SWEEP_FLAG_IDX];
}
enum PathInterpolationResult {
eCannotInterpolate,
eRequiresConversion,
@ -139,12 +124,6 @@ CanInterpolate(const SVGPathDataAndOwner& aStart,
PRUint32 startType = SVGPathSegUtils::DecodeType(*pStart);
PRUint32 endType = SVGPathSegUtils::DecodeType(*pEnd);
if (SVGPathSegUtils::IsArcType(startType) &&
SVGPathSegUtils::IsArcType(endType) &&
ArcFlagsDiffer(pStart, pEnd)) {
return eCannotInterpolate;
}
if (startType != endType) {
if (!SVGPathSegUtils::SameTypeModuloRelativeness(startType, endType)) {
return eCannotInterpolate;
@ -215,25 +194,22 @@ AddWeightedPathSegs(double aCoeff1,
NS_ABORT_IF_FALSE(!aSeg1 || SVGPathSegUtils::DecodeType(*aSeg1) == segType,
"unexpected segment type");
// FIRST: Directly copy the arguments that don't make sense to add.
aResultSeg[0] = aSeg2[0]; // encoded segment type
bool isArcType = SVGPathSegUtils::IsArcType(segType);
if (isArcType) {
// Copy boolean arc flags.
NS_ABORT_IF_FALSE(!aSeg1 || !ArcFlagsDiffer(aSeg1, aSeg2),
"Expecting arc flags to match");
aResultSeg[LARGE_ARC_FLAG_IDX] = aSeg2[LARGE_ARC_FLAG_IDX];
aResultSeg[SWEEP_FLAG_IDX] = aSeg2[SWEEP_FLAG_IDX];
}
// SECOND: Add the arguments that are supposed to be added.
// FIRST: Add all the arguments.
// (The 1's below are to account for segment type)
PRUint32 numArgs = SVGPathSegUtils::ArgCountForType(segType);
for (PRUint32 i = 1; i < 1 + numArgs; ++i) {
// Need to skip arc flags for arc-type segments. (already handled them)
if (!(isArcType && (i == LARGE_ARC_FLAG_IDX || i == SWEEP_FLAG_IDX))) {
aResultSeg[i] = (aSeg1 ? aCoeff1 * aSeg1[i] : 0.0) + aCoeff2 * aSeg2[i];
aResultSeg[i] = (aSeg1 ? aCoeff1 * aSeg1[i] : 0.0) + aCoeff2 * aSeg2[i];
}
// SECOND: ensure non-zero flags become 1.
if (SVGPathSegUtils::IsArcType(segType)) {
if (aResultSeg[LARGE_ARC_FLAG_IDX] != 0.0f) {
aResultSeg[LARGE_ARC_FLAG_IDX] = 1.0f;
}
if (aResultSeg[SWEEP_FLAG_IDX] != 0.0f) {
aResultSeg[SWEEP_FLAG_IDX] = 1.0f;
}
}

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

@ -138,10 +138,10 @@ var gSuffixes = {
[40, 50, 60, 70, 80, 90], [50, 70, 90, 110, 130, 150]],
QQ: [[10, 20, 30, 40], [50, 60, 70, 80], [30, 40, 50, 60], [40, 60, 80, 100]],
qq: [[10, 20, 30, 40], [50, 60, 70, 80], [30, 40, 50, 60], [40, 60, 80, 100]],
AA: [[10, 20, 30, 0, 0, 40, 50], [60, 70, 80, 0, 0, 90, 100],
[35, 45, 55, 0, 0, 65, 75], [45, 65, 85, 0, 0, 105, 125]],
aa: [[10, 20, 30, 0, 0, 40, 50], [60, 70, 80, 0, 0, 90, 100],
[35, 45, 55, 0, 0, 65, 75], [45, 65, 85, 0, 0, 105, 125]],
AA: [[10, 20, 30, 1, 0, 40, 50], [60, 70, 80, 0, 0, 90, 100],
[35, 45, 55, 1, 0, 65, 75], [45, 65, 85, 1, 0, 105, 125]],
aa: [[10, 20, 30, 0, 1, 40, 50], [60, 70, 80, 0, 0, 90, 100],
[35, 45, 55, 0, 1, 65, 75], [45, 65, 85, 0, 1, 105, 125]],
HH: [[10], [20], [15], [25]],
hh: [[10], [20], [15], [25]],
VV: [[10], [20], [15], [25]],
@ -286,17 +286,6 @@ function run()
}
}
// Test that differences in arc flag parameters cause the
// interpolation/addition not to occur.
addTest(1, "M100,100",
"A", [10, 20, 30, 0, 0, 40, 50],
"a", [60, 70, 80, 0, 1, 90, 100],
"a", [60, 70, 80, 0, 1, 90, 100], additive);
addTest(1, "M100,100",
"A", [10, 20, 30, 0, 0, 40, 50],
"a", [60, 70, 80, 1, 0, 90, 100],
"a", [60, 70, 80, 1, 0, 90, 100], additive);
// Test all pairs of segment types that cannot be interpolated between.
for each (let fromType in gTypes) {
let fromArguments = generatePathSegmentArguments(fromType, 0);

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

@ -1643,7 +1643,7 @@ nsJSContext::ExecuteScript(void *aScriptObject,
nsCOMPtr<nsIPrincipal> principal;
rv = sSecurityManager->GetObjectPrincipal(mContext,
JS_GetObjectFromScript(script),
JS_GetGlobalFromScript(script),
getter_AddRefs(principal));
NS_ENSURE_SUCCESS(rv, rv);

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

@ -560,8 +560,8 @@ TransactionPoolEventTarget::Dispatch(nsIRunnable* aRunnable,
NS_ASSERTION(aRunnable, "Null pointer!");
NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "Unsupported!");
TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
NS_ENSURE_TRUE(pool, NS_ERROR_FAILURE);
TransactionThreadPool* pool = TransactionThreadPool::Get();
NS_ASSERTION(pool, "This should never be null!");
return pool->Dispatch(mTransaction, aRunnable, false, nsnull);
}

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

@ -125,6 +125,11 @@ public:
static IDBTransaction* GetCurrentTransaction();
bool HasTransaction()
{
return mTransaction;
}
nsISupports* GetSource()
{
return mRequest ? mRequest->Source() : nsnull;

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

@ -85,7 +85,8 @@ EnumerateObjectStoreNames(const nsAString& aKey,
DatabaseInfo::DatabaseInfo()
: id(0),
nextObjectStoreId(1),
nextIndexId(1)
nextIndexId(1),
runningVersionChange(false)
{
MOZ_COUNT_CTOR(DatabaseInfo);
}

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

@ -54,7 +54,8 @@ struct DatabaseInfo
~DatabaseInfo();
#else
DatabaseInfo()
: id(0), nextObjectStoreId(1), nextIndexId(1) { }
: id(0), nextObjectStoreId(1), nextIndexId(1), runningVersionChange(false)
{ }
#endif
static bool Get(PRUint32 aId,
@ -73,6 +74,7 @@ struct DatabaseInfo
nsString filePath;
PRInt64 nextObjectStoreId;
PRInt64 nextIndexId;
bool runningVersionChange;
nsAutoRefCnt referenceCount;
};

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

@ -428,6 +428,34 @@ IDBDatabase::IsClosed()
return mClosed;
}
void
IDBDatabase::EnterSetVersionTransaction()
{
DatabaseInfo* dbInfo;
if (!DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
NS_ERROR("This should never fail!");
}
NS_ASSERTION(!dbInfo->runningVersionChange, "How did that happen?");
dbInfo->runningVersionChange = true;
}
void
IDBDatabase::ExitSetVersionTransaction()
{
DatabaseInfo* dbInfo;
if (!DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
NS_ERROR("This should never fail!");
}
NS_ASSERTION(dbInfo->runningVersionChange, "How did that happen?");
dbInfo->runningVersionChange = false;
IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
NS_ASSERTION(manager, "We should always have a manager here");
manager->UnblockSetVersionRunnable(this);
}
void
IDBDatabase::OnUnlink()
{
@ -710,6 +738,10 @@ IDBDatabase::Transaction(nsIVariant* aStoreNames,
NS_ERROR("This should never fail!");
}
if (info->runningVersionChange) {
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
}
nsTArray<nsString> storesToOpen;
switch (type) {

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

@ -135,6 +135,9 @@ public:
// Whether or not the database has had Close called on it.
bool IsClosed();
void EnterSetVersionTransaction();
void ExitSetVersionTransaction();
private:
IDBDatabase();
~IDBDatabase();

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

@ -693,19 +693,15 @@ IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase)
// Now run the helper if there are no more live databases.
if (runnable->mHelper && runnable->mDatabases.IsEmpty()) {
// Don't hold the callback alive longer than necessary.
nsRefPtr<AsyncConnectionHelper> helper;
helper.swap(runnable->mHelper);
// At this point, all databases are closed, so no new transactions can
// be started. There may, however, still be outstanding transactions
// that have not completed. We need to wait for those before we
// dispatch the helper.
if (NS_FAILED(helper->DispatchToTransactionPool())) {
NS_WARNING("Failed to dispatch to thread pool!");
}
TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
// Now wait for the transaction to complete. Completing the transaction
// will be our cue to remove the SetVersionRunnable from our list and
// therefore allow other SetVersion requests to begin.
TransactionThreadPool* pool = TransactionThreadPool::Get();
NS_ASSERTION(pool, "This should never be null!");
nsRefPtr<WaitForTransactionsToFinishRunnable> waitRunnable =
new WaitForTransactionsToFinishRunnable(runnable);
// All other databases should be closed, so we only need to wait on this
// one.
@ -714,8 +710,8 @@ IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase)
NS_ERROR("This should never fail!");
}
// Use the SetVersionRunnable as the callback.
if (!pool->WaitForAllDatabasesToComplete(array, runnable)) {
// Use the WaitForTransactionsToFinishRunnable as the callback.
if (!pool->WaitForAllDatabasesToComplete(array, waitRunnable)) {
NS_WARNING("Failed to wait for transaction to complete!");
}
}
@ -724,6 +720,27 @@ IndexedDatabaseManager::OnDatabaseClosed(IDBDatabase* aDatabase)
}
}
void
IndexedDatabaseManager::UnblockSetVersionRunnable(IDBDatabase* aDatabase)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aDatabase, "Null pointer!");
// Check through the list of SetVersionRunnables to find the one we're seeking.
for (PRUint32 index = 0; index < mSetVersionRunnables.Length(); index++) {
nsRefPtr<SetVersionRunnable>& runnable = mSetVersionRunnables[index];
if (runnable->mRequestingDatabase->Id() == aDatabase->Id()) {
NS_ASSERTION(!runnable->mHelper,
"Why are we unblocking a runnable if the helper didn't run?");
NS_DispatchToCurrentThread(runnable);
return;
}
}
NS_NOTREACHED("How did we get here!");
}
// static
bool
IndexedDatabaseManager::SetCurrentDatabase(IDBDatabase* aDatabase)
@ -1283,3 +1300,39 @@ IndexedDatabaseManager::SetVersionRunnable::Run()
return NS_OK;
}
NS_IMPL_THREADSAFE_ISUPPORTS1(IndexedDatabaseManager::WaitForTransactionsToFinishRunnable,
nsIRunnable)
NS_IMETHODIMP
IndexedDatabaseManager::WaitForTransactionsToFinishRunnable::Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// Don't hold the callback alive longer than necessary.
nsRefPtr<AsyncConnectionHelper> helper;
helper.swap(mRunnable->mHelper);
nsRefPtr<SetVersionRunnable> runnable;
runnable.swap(mRunnable);
// If the helper has a transaction, dispatch it to the transaction
// threadpool.
if (helper->HasTransaction()) {
if (NS_FAILED(helper->DispatchToTransactionPool())) {
NS_WARNING("Failed to dispatch to thread pool!");
}
}
// Otherwise, dispatch it to the IO thread.
else {
IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
NS_ASSERTION(manager, "We should definitely have a manager here");
helper->Dispatch(manager->IOThread());
}
// The helper is responsible for calling
// IndexedDatabaseManager::UnblockSetVersionRunnable.
return NS_OK;
}

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

@ -204,6 +204,8 @@ private:
// Called when AsyncUsageRunnable has finished its Run() method.
inline void OnUsageCheckComplete(AsyncUsageRunnable* aRunnable);
void UnblockSetVersionRunnable(IDBDatabase* aDatabase);
// Responsible for waiting until all databases have been closed before running
// the version change transaction. Created when
// IndexedDatabaseManager::SetDatabaseVersion is called. Runs only once on the
@ -227,6 +229,26 @@ private:
// Called when SetVersionRunnable has finished its Run() method.
inline void OnSetVersionRunnableComplete(SetVersionRunnable* aRunnable);
// A callback runnable used by the TransactionPool when it's safe to proceed
// with a SetVersion/DeleteDatabase/etc.
class WaitForTransactionsToFinishRunnable : public nsIRunnable
{
public:
WaitForTransactionsToFinishRunnable(SetVersionRunnable* aRunnable)
: mRunnable(aRunnable)
{
NS_ASSERTION(mRunnable, "Why don't we have a runnable?");
NS_ASSERTION(mRunnable->mDatabases.IsEmpty(), "We're here too early!");
}
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
private:
nsRefPtr<SetVersionRunnable> mRunnable;
};
// Maintains a list of live databases per origin.
nsClassHashtable<nsCStringHashKey, nsTArray<IDBDatabase*> > mLiveDatabases;

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

@ -495,10 +495,13 @@ public:
NS_DECL_ISUPPORTS_INHERITED
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
nsresult GetSuccessResult(JSContext* aCx,
jsval* aVal);
protected:
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
nsresult Init();
// SetVersionHelper never fires an error event at the request. It hands that
// responsibility back to the OpenDatabaseHelper
void OnError() { }
@ -554,6 +557,8 @@ OpenDatabaseHelper::DoDatabaseWork()
}
#endif
mState = eFiringEvents; // In case we fail somewhere along the line.
if (IndexedDatabaseManager::IsShuttingDown()) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
@ -646,9 +651,10 @@ OpenDatabaseHelper::DoDatabaseWork()
return NS_ERROR_DOM_INDEXEDDB_VERSION_ERR;
}
mState = mCurrentVersion != mRequestedVersion ?
eSetVersionPending :
eFiringEvents;
if (mCurrentVersion != mRequestedVersion) {
mState = eSetVersionPending;
}
return NS_OK;
}
@ -684,6 +690,7 @@ OpenDatabaseHelper::StartSetVersion()
// The SetVersionHelper is responsible for dispatching us back to the
// main thread again and changing the state to eSetVersionCompleted.
mState = eSetVersionPending;
return NS_OK;
}
@ -711,6 +718,12 @@ OpenDatabaseHelper::Run()
mState == eSetVersionCompleted, "Why are we here?");
if (mState == eSetVersionCompleted) {
// Allow transaction creation/other version change transactions to proceed
// before we fire events. Other version changes will be postd to the end
// of the event loop, and will be behind whatever the page does in
// its error/success event handlers.
mDatabase->ExitSetVersionTransaction();
mState = eFiringEvents;
} else {
// Notify the request that we're done, but only if we didn't just finish
@ -865,6 +878,15 @@ OpenDatabaseHelper::NotifySetVersionFinished()
return NS_DispatchToCurrentThread(this);
}
void
OpenDatabaseHelper::BlockDatabase()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(mDatabase, "This is going bad fast.");
mDatabase->EnterSetVersionTransaction();
}
void
OpenDatabaseHelper::DispatchSuccessEvent()
{
@ -916,6 +938,15 @@ OpenDatabaseHelper::ReleaseMainThreadObjects()
NS_IMPL_ISUPPORTS_INHERITED0(SetVersionHelper, AsyncConnectionHelper);
nsresult
SetVersionHelper::Init()
{
// Block transaction creation until we are done.
mOpenHelper->BlockDatabase();
return NS_OK;
}
nsresult
SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{

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

@ -82,6 +82,7 @@ public:
}
nsresult NotifySetVersionFinished();
void BlockDatabase();
protected:
// Methods only called on the main thread

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

@ -238,7 +238,6 @@ TransactionThreadPool::FinishTransaction(IDBTransaction* aTransaction)
#ifdef DEBUG
if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
NS_ASSERTION(dbTransactionInfo->locked, "Should be locked!");
NS_ASSERTION(transactionCount == 1,
"More transactions running than should be!");
}
@ -344,10 +343,6 @@ TransactionThreadPool::TransactionCanRun(IDBTransaction* aTransaction,
PRUint32 transactionCount = transactionsInProgress.Length();
NS_ASSERTION(transactionCount, "Should never be 0!");
if (mode == IDBTransaction::VERSION_CHANGE) {
dbTransactionInfo->lockPending = true;
}
for (PRUint32 index = 0; index < transactionCount; index++) {
// See if this transaction is in out list of current transactions.
const TransactionInfo& info = transactionsInProgress[index];
@ -358,11 +353,7 @@ TransactionThreadPool::TransactionCanRun(IDBTransaction* aTransaction,
}
}
if (dbTransactionInfo->locked || dbTransactionInfo->lockPending) {
*aCanRun = false;
*aExistingQueue = nsnull;
return NS_OK;
}
NS_ASSERTION(mode != IDBTransaction::VERSION_CHANGE, "How did we get here?");
bool writeOverlap;
nsresult rv =
@ -448,11 +439,6 @@ TransactionThreadPool::Dispatch(IDBTransaction* aTransaction,
dbTransactionInfo = autoDBTransactionInfo;
}
if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
NS_ASSERTION(!dbTransactionInfo->locked, "Already locked?!");
dbTransactionInfo->locked = true;
}
const nsTArray<nsString>& objectStoreNames = aTransaction->mObjectStoreNames;
nsTArray<nsString>& storesInUse =

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

@ -123,12 +123,6 @@ protected:
struct DatabaseTransactionInfo
{
DatabaseTransactionInfo()
: locked(false), lockPending(false)
{ }
bool locked;
bool lockPending;
nsTArray<TransactionInfo> transactions;
nsTArray<nsString> storesReading;
nsTArray<nsString> storesWriting;

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

@ -98,6 +98,7 @@ TEST_FILES = \
test_setVersion.html \
test_setVersion_abort.html \
test_setVersion_events.html \
test_setVersion_exclusion.html \
test_writer_starvation.html \
third_party_iframe1.html \
third_party_iframe2.html \

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

@ -69,6 +69,9 @@
db.createObjectStore("foo", { autoIncrement: true });
request.onsuccess = grabEventAndContinueHandler;
yield;
setTimeout(testFinishedCallback, 0, "ready");
yield;
}

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

@ -104,7 +104,7 @@
db.onerror = errorEventCounter;
db.addEventListener("error", errorEventCounter, true);
event.target.transaction.oncomplete = grabEventAndContinueHandler;
event.target.onsuccess = grabEventAndContinueHandler;
db.createObjectStore("foo", { autoIncrement: true });
yield;

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

@ -12,7 +12,7 @@ function startDBWork() {
}
var store = db.createObjectStore("mystore");
store.add({ hello: "world" }, 42);
trans.oncomplete = madeMod;
e.target.onsuccess = madeMod;
};
}

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

@ -33,6 +33,9 @@
let key = event.target.result;
ok(key, "Added entry");
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let objectStore = db.transaction("foo").objectStore("foo");
let first = objectStore.index("first");

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

@ -25,7 +25,7 @@
let db = request.result;
event.target.transaction.oncomplete = continueToNextStep;
event.target.onsuccess = continueToNextStep;
let objectStore = db.createObjectStore("foo", { autoIncrement: true });

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

@ -23,7 +23,7 @@
let db = event.target.result;
db.onerror = errorHandler;
event.target.transaction.oncomplete = continueToNextStep;
event.target.onsuccess = continueToNextStep;
// Make object store, add data.
let objectStore = db.createObjectStore("foo", { keyPath: "id" });
@ -39,7 +39,7 @@
let db2 = event.target.result;
db2.onerror = errorHandler;
event.target.transaction.oncomplete = continueToNextStep;
event.target.onsuccess = continueToNextStep;
// Create index.
event.target.transaction.objectStore("foo").createIndex("foo", "num");

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

@ -35,7 +35,7 @@
let event = yield;
let db = event.target.result;
event.target.transaction.oncomplete = continueToNextStep;
event.target.onsuccess = continueToNextStep;
let objectStore = db.createObjectStore("foo", { keyPath: "ss" });
objectStore.createIndex("name", "name", { unique: true });

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

@ -26,6 +26,7 @@
let objectStore = db.createObjectStore("foo", { autoIncrement: true });
request.onsuccess = grabEventAndContinueHandler;
request = objectStore.getAll();
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
@ -46,6 +47,7 @@
}
}
yield;
yield;
request = db.transaction("foo").objectStore("foo").getAll();
request.onerror = errorHandler;

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

@ -60,6 +60,7 @@
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
@ -78,7 +79,7 @@
}
}
}
event = yield;
yield;
ok(true, "1");
// Now create the indexes.
@ -88,7 +89,6 @@
}
is(objectStore.indexNames.length, indexData.length, "Good index count");
continueToNextStep();
yield;
ok(true, "2");

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

@ -60,6 +60,7 @@
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
@ -87,7 +88,6 @@
}
is(objectStore.indexNames.length, indexData.length, "Good index count");
continueToNextStep();
yield;
objectStore = db.transaction(objectStoreName)

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

@ -37,7 +37,7 @@
let db = event.target.result;
db.onerror = errorHandler;
event.target.transaction.oncomplete = continueToNextStep;
event.target.onsuccess = continueToNextStep;
for (let objectStoreIndex in objectStoreData) {
const objectStoreInfo = objectStoreData[objectStoreIndex];

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

@ -71,6 +71,7 @@
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
@ -97,7 +98,6 @@
indexData[i].options);
}
is(objectStore.indexNames.length, indexData.length, "Good index count");
continueToNextStep();
yield;
objectStore = db.transaction(objectStoreName)

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

@ -51,6 +51,7 @@
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
@ -87,6 +88,7 @@
}
}
yield;
yield;
objectStore = db.transaction(objectStoreName)
.objectStore(objectStoreName);

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

@ -28,7 +28,7 @@
let index2 = objectStore2.index("bar");
ok(index1 === index2, "Got same indexes");
transaction.oncomplete = continueToNextStep;
request.onsuccess = continueToNextStep;
yield;
transaction = db.transaction("foo");

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

@ -29,7 +29,7 @@
autoIncrement: true });
let index = objectStore.createIndex("foo", "index");
event.target.transaction.oncomplete = continueToNextStep;
event.target.onsuccess = continueToNextStep;
yield;
objectStore = db.transaction("foo", IDBTransaction.READ_WRITE)

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

@ -20,6 +20,7 @@
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
@ -31,7 +32,6 @@
is(db.objectStoreNames.length, 1, "Bad objectStores list");
is(db.objectStoreNames.item(0), objectStoreName, "Bad name");
continueToNextStep();
yield;
objectStore = db.transaction(objectStoreName).objectStore(objectStoreName);

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

@ -26,7 +26,7 @@
let db = event.target.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
event.target.transaction.oncomplete = grabEventAndContinueHandler;
event.target.onsuccess = grabEventAndContinueHandler;
for (let i in objectStores) {
db.createObjectStore(objectStores[i], { autoIncrement: true });
}

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

@ -22,6 +22,7 @@
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
@ -29,6 +30,8 @@
db.createObjectStore(osName, { autoIncrement: "true" });
yield;
let key1, key2;
request = db.transaction([osName], READ_WRITE)

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

@ -0,0 +1,90 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Property Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
function testSteps()
{
const name = window.location.pathname;
let request = mozIndexedDB.open(name, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
let request2 = mozIndexedDB.open(name, 2);
request2.onerror = errorHandler;
request2.onupgradeneeded = unexpectedSuccessHandler;
let event = yield;
is(event.type, "upgradeneeded", "Expect an upgradeneeded event");
is(event.target, request, "Event should be fired on the request");
ok(event.target.result instanceof IDBDatabase, "Expect a database here");
let db = event.target.result;
is(db.version, 1, "Database has correct version");
db.onupgradeneeded = function() {
ok(false, "our ongoing VERSION_CHANGE transaction should exclude any others!");
}
db.createObjectStore("foo");
try {
db.transaction("foo");
ok(false, "Transactions should be disallowed now!");
} catch (e) {
ok(e instanceof IDBDatabaseException, "Expect an IDBException");
is(e.code, IDBDatabaseException.NOT_ALLOWED_ERR, "Expect a NOT_ALLOWED_ERR");
}
request.transaction.oncomplete = grabEventAndContinueHandler;
yield;
// The database is still not fully open here.
try {
db.transaction("foo");
ok(false, "Transactions should be disallowed now!");
} catch (e) {
ok(e instanceof IDBDatabaseException, "Expect an IDBException");
is(e.code, IDBDatabaseException.NOT_ALLOWED_ERR, "Expect a NOT_ALLOWED_ERR");
}
request.onsuccess = grabEventAndContinueHandler;
yield;
db.onversionchange = function() {
ok(true, "next setVersion was unblocked appropriately");
db.close();
}
try {
db.transaction("foo");
ok(true, "Transactions should be allowed now!");
} catch (e) {
ok(false, "Transactions should be allowed now!");
}
request2.onupgradeneeded = null;
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

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

@ -19,7 +19,7 @@
let db = event.target.result;
event.target.transaction.oncomplete = continueToNextStep;
event.target.onsuccess = continueToNextStep;
let objectStore = db.createObjectStore("foo");
objectStore.add({}, 1).onerror = errorHandler;

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

@ -29,6 +29,7 @@
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
@ -157,6 +158,8 @@
ok(true, "RemoveIndex threw");
}
yield;
request = db.transaction("foo", READ_WRITE).objectStore("foo").add({});
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;

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

@ -20,7 +20,7 @@
let db = event.target.result;
db.onerror = errorHandler;
event.target.transaction.oncomplete = continueToNextStep;
event.target.onsuccess = continueToNextStep;
db.createObjectStore("foo", { autoIncrement: true });
yield;

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

@ -20,7 +20,7 @@
let db = event.target.result;
db.onerror = errorHandler;
event.target.transaction.oncomplete = continueToNextStep;
event.target.onsuccess = continueToNextStep;
db.createObjectStore("foo");
yield;

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

@ -23,6 +23,7 @@
let request = mozIndexedDB.open(name, 1, description);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
@ -39,7 +40,6 @@
let key = event.target.result;
ok(key, "Got a key");
SimpleTest.executeSoon(function() { testGenerator.next(); });
yield;
let continueReading = true;

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

@ -182,7 +182,7 @@ CPPSRCS = \
# doing!
INSTALLED_HEADERS = \
js-config.h \
jsautocfg.h \
jscpucfg.h \
$(CURDIR)/jsautokw.h \
js.msg \
jsalloc.h \
@ -542,10 +542,6 @@ else
CPPSRCS += pm_stub.cpp
endif
ifeq ($(OS_ARCH),WINNT)
INSTALLED_HEADERS += jscpucfg.h
endif
EXPORTS = $(INSTALLED_HEADERS)
DASH_R = -r
@ -760,12 +756,6 @@ DEFINES += -DIMPL_MFBT
INCLUDES += -I$(srcdir)
GARBAGE += jscpucfg.o jsautocfg.h jsautocfg.tmp jscpucfg
ifneq (,$(CROSS_COMPILE)$(filter-out WINNT,$(OS_ARCH)))
TARGETS += jscpucfg$(HOST_BIN_SUFFIX)
endif
ifdef JS_THREADSAFE
DEFINES += -DJS_THREADSAFE
endif
@ -880,34 +870,6 @@ jsdtoa.o: jsdtoa.cpp Makefile.in
$(CXX) -o $@ -c $(filter-out $(MOZ_OPTIMIZE_FLAGS), $(COMPILE_CFLAGS)) $<
endif
export:: jsautocfg.h
ifeq (,$(CROSS_COMPILE)$(GNU_CC)$(filter-out WINNT,$(OS_ARCH)))
jsautocfg.h:
$(TOUCH) $@
else
jsautocfg.h: jscpucfg$(HOST_BIN_SUFFIX)
@$(RM) $@ jsautocfg.tmp
./jscpucfg > jsautocfg.tmp
mv jsautocfg.tmp $@
endif
# jscpucfg is a strange target
# Needs to be built with the host compiler but needs to include
# the mdcpucfg for the target so it needs the appropriate target defines
ifdef HOST_NSPR_MDCPUCFG
HOST_CXX := $(HOST_CXX) -DMDCPUCFG=$(TARGET_NSPR_MDCPUCFG)
HOST_CXXFLAGS := $(patsubst -DXP_%,,$(HOST_CXXFLAGS))
endif
ifdef CROSS_COMPILE
# jscpucfg needs to know when it's supposed to produce a config for the target
JSCPUCFG_DEFINES = $(ACDEFINES)
endif
jscpucfg$(HOST_BIN_SUFFIX): jscpucfg.cpp Makefile.in
$(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) $(HOST_OUTOPTION)$@ $<
# Compute the linker flags that programs linking against SpiderMonkey should
# pass to get SpiderMonkey and its dependencies, beyond just the -L and -l
# for the SpiderMonkey library itself.

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

@ -2718,6 +2718,11 @@ fi
MOZ_ALIGN_OF_TYPE(JS_ALIGN_OF_POINTER, void*, 2 4 8 16)
MOZ_SIZE_OF_TYPE(JS_BYTES_PER_DOUBLE, double, 6 8 10 12 14)
AC_CHECK_HEADERS(endian.h)
if test "$ac_cv_header_endian_h" = yes; then
AC_DEFINE(JS_HAVE_ENDIAN_H)
fi
dnl Check for int16_t, int32_t, int64_t, int64, uint, uint_t, and uint16_t.
dnl ========================================================
AC_MSG_CHECKING(for int16_t)

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

@ -51,8 +51,6 @@
using namespace js;
using namespace js::frontend;
namespace js {
/*
* Compile a top-level script.
*/
@ -74,7 +72,7 @@ BytecodeCompiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame
bool inDirectivePrologue;
JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_NEED_MUTABLE_SCRIPT |
TCF_COMPILE_FOR_EVAL | TCF_NEED_SCRIPT_OBJECT)));
TCF_COMPILE_FOR_EVAL | TCF_NEED_SCRIPT_GLOBAL)));
/*
* The scripted callerFrame can only be given for compile-and-go scripts
@ -476,5 +474,3 @@ BytecodeCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipa
return pn != NULL;
}
} /* namespace js */

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

@ -93,9 +93,6 @@ using namespace js::frontend;
extern uint8 js_opcode2extra[];
#endif
namespace js {
namespace frontend {
static JSBool
NewTryNote(JSContext *cx, CodeGenerator *cg, JSTryNoteKind kind, uintN stackDepth,
size_t start, size_t end);
@ -106,7 +103,8 @@ EmitIndexOp(JSContext *cx, JSOp op, uintN index, CodeGenerator *cg, JSOp *psuffi
static JSBool
EmitLeaveBlock(JSContext *cx, CodeGenerator *cg, JSOp op, ObjectBox *box);
} /* namespace frontend */
static JSBool
SetSrcNoteOffset(JSContext *cx, CodeGenerator *cg, uintN index, uintN which, ptrdiff_t offset);
void
TreeContext::trace(JSTracer *trc)
@ -162,8 +160,6 @@ CodeGenerator::~CodeGenerator()
cx->free_(spanDeps);
}
namespace frontend {
static ptrdiff_t
EmitCheck(JSContext *cx, CodeGenerator *cg, ptrdiff_t delta)
{
@ -269,7 +265,7 @@ UpdateDecomposeLength(CodeGenerator *cg, uintN start)
}
ptrdiff_t
Emit1(JSContext *cx, CodeGenerator *cg, JSOp op)
frontend::Emit1(JSContext *cx, CodeGenerator *cg, JSOp op)
{
ptrdiff_t offset = EmitCheck(cx, cg, 1);
@ -281,7 +277,7 @@ Emit1(JSContext *cx, CodeGenerator *cg, JSOp op)
}
ptrdiff_t
Emit2(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1)
frontend::Emit2(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1)
{
ptrdiff_t offset = EmitCheck(cx, cg, 2);
@ -296,8 +292,8 @@ Emit2(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1)
}
ptrdiff_t
Emit3(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1,
jsbytecode op2)
frontend::Emit3(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1,
jsbytecode op2)
{
ptrdiff_t offset = EmitCheck(cx, cg, 3);
@ -313,7 +309,7 @@ Emit3(JSContext *cx, CodeGenerator *cg, JSOp op, jsbytecode op1,
}
ptrdiff_t
Emit5(JSContext *cx, CodeGenerator *cg, JSOp op, uint16 op1, uint16 op2)
frontend::Emit5(JSContext *cx, CodeGenerator *cg, JSOp op, uint16 op1, uint16 op2)
{
ptrdiff_t offset = EmitCheck(cx, cg, 5);
@ -331,7 +327,7 @@ Emit5(JSContext *cx, CodeGenerator *cg, JSOp op, uint16 op1, uint16 op2)
}
ptrdiff_t
EmitN(JSContext *cx, CodeGenerator *cg, JSOp op, size_t extra)
frontend::EmitN(JSContext *cx, CodeGenerator *cg, JSOp op, size_t extra)
{
ptrdiff_t length = 1 + (ptrdiff_t)extra;
ptrdiff_t offset = EmitCheck(cx, cg, length);
@ -558,7 +554,8 @@ AddJumpTarget(AddJumpTargetArgs *args, JumpTarget **jtp)
}
#ifdef DEBUG_brendan
static int AVLCheck(JumpTarget *jt)
static int
AVLCheck(JumpTarget *jt)
{
int lh, rh;
@ -1267,7 +1264,7 @@ GetJumpOffset(CodeGenerator *cg, jsbytecode *pc)
}
JSBool
SetJumpOffset(JSContext *cx, CodeGenerator *cg, jsbytecode *pc, ptrdiff_t off)
frontend::SetJumpOffset(JSContext *cx, CodeGenerator *cg, jsbytecode *pc, ptrdiff_t off)
{
if (!cg->spanDeps) {
if (JUMP_OFFSET_MIN <= off && off <= JUMP_OFFSET_MAX) {
@ -1282,8 +1279,6 @@ SetJumpOffset(JSContext *cx, CodeGenerator *cg, jsbytecode *pc, ptrdiff_t off)
return SetSpanDepTarget(cx, cg, GetSpanDep(cg, pc), off);
}
} /* namespace frontend */
bool
TreeContext::inStatement(StmtType type)
{
@ -1344,10 +1339,8 @@ TreeContext::skipSpansGenerator(unsigned skip)
return false;
}
namespace frontend {
bool
SetStaticLevel(TreeContext *tc, uintN staticLevel)
frontend::SetStaticLevel(TreeContext *tc, uintN staticLevel)
{
/*
* This is a lot simpler than error-checking every UpvarCookie::set, and
@ -1363,7 +1356,7 @@ SetStaticLevel(TreeContext *tc, uintN staticLevel)
}
bool
GenerateBlockId(TreeContext *tc, uint32& blockid)
frontend::GenerateBlockId(TreeContext *tc, uint32& blockid)
{
if (tc->blockidGen == JS_BIT(20)) {
JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL,
@ -1375,7 +1368,7 @@ GenerateBlockId(TreeContext *tc, uint32& blockid)
}
void
PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top)
frontend::PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top)
{
stmt->type = type;
stmt->flags = 0;
@ -1394,7 +1387,7 @@ PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top)
}
void
PushBlockScope(TreeContext *tc, StmtInfo *stmt, ObjectBox *blockBox, ptrdiff_t top)
frontend::PushBlockScope(TreeContext *tc, StmtInfo *stmt, ObjectBox *blockBox, ptrdiff_t top)
{
PushStatement(tc, stmt, STMT_BLOCK, top);
stmt->flags |= SIF_SCOPE;
@ -1680,7 +1673,7 @@ BackPatch(JSContext *cx, CodeGenerator *cg, ptrdiff_t last, jsbytecode *target,
}
void
PopStatementTC(TreeContext *tc)
frontend::PopStatementTC(TreeContext *tc)
{
StmtInfo *stmt = tc->topStmt;
tc->topStmt = stmt->down;
@ -1693,7 +1686,7 @@ PopStatementTC(TreeContext *tc)
}
JSBool
PopStatementCG(JSContext *cx, CodeGenerator *cg)
frontend::PopStatementCG(JSContext *cx, CodeGenerator *cg)
{
StmtInfo *stmt = cg->topStmt;
if (!STMT_IS_TRYING(stmt) &&
@ -1707,7 +1700,7 @@ PopStatementCG(JSContext *cx, CodeGenerator *cg)
}
JSBool
DefineCompileTimeConstant(JSContext *cx, CodeGenerator *cg, JSAtom *atom, ParseNode *pn)
frontend::DefineCompileTimeConstant(JSContext *cx, CodeGenerator *cg, JSAtom *atom, ParseNode *pn)
{
/* XXX just do numbers for now */
if (pn->isKind(TOK_NUMBER)) {
@ -1718,7 +1711,7 @@ DefineCompileTimeConstant(JSContext *cx, CodeGenerator *cg, JSAtom *atom, ParseN
}
StmtInfo *
LexicalLookup(TreeContext *tc, JSAtom *atom, jsint *slotp, StmtInfo *stmt)
frontend::LexicalLookup(TreeContext *tc, JSAtom *atom, jsint *slotp, StmtInfo *stmt)
{
if (!stmt)
stmt = tc->topScopeStmt;
@ -1960,16 +1953,12 @@ EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index, CodeGenerator *
return bigSuffix == JSOP_NOP || Emit1(cx, cg, bigSuffix) >= 0;
}
} /* namespace frontend */
bool
CodeGenerator::shouldNoteClosedName(ParseNode *pn)
{
return !callsEval() && pn->isDefn() && pn->isClosed();
}
namespace frontend {
/*
* Adjust the slot for a block local to account for the number of variables
* that share the same index space with locals. Due to the incremental code
@ -2524,8 +2513,6 @@ BindNameToSlot(JSContext *cx, CodeGenerator *cg, ParseNode *pn)
return JS_TRUE;
}
} /* namespace frontend */
bool
CodeGenerator::addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie)
{
@ -2560,8 +2547,6 @@ CodeGenerator::addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie)
return globalMap->add(p, atom, globalUseIndex);
}
namespace frontend {
/*
* If pn contains a useful expression, return true with *answer set to true.
* If pn contains a useless expression, return true with *answer set to false.
@ -3924,7 +3909,7 @@ bad:
}
JSBool
EmitFunctionScript(JSContext *cx, CodeGenerator *cg, ParseNode *body)
frontend::EmitFunctionScript(JSContext *cx, CodeGenerator *cg, ParseNode *body)
{
/*
* The decompiler has assumptions about what may occur immediately after
@ -4823,8 +4808,6 @@ EmitEndInit(JSContext *cx, CodeGenerator *cg, uint32 count)
return Emit1(cx, cg, JSOP_ENDINIT) >= 0;
}
} /* namespace frontend */
bool
ParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
{
@ -4916,8 +4899,6 @@ ParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
return false;
}
namespace frontend {
static bool
EmitSingletonInitialiser(JSContext *cx, CodeGenerator *cg, ParseNode *pn)
{
@ -5858,7 +5839,7 @@ EmitFor(JSContext *cx, CodeGenerator *cg, ParseNode *pn, ptrdiff_t top)
}
JSBool
EmitTree(JSContext *cx, CodeGenerator *cg, ParseNode *pn)
frontend::EmitTree(JSContext *cx, CodeGenerator *cg, ParseNode *pn)
{
JSBool useful, wantval;
StmtInfo stmtInfo;
@ -7464,7 +7445,7 @@ AllocSrcNote(JSContext *cx, CodeGenerator *cg)
}
intN
NewSrcNote(JSContext *cx, CodeGenerator *cg, SrcNoteType type)
frontend::NewSrcNote(JSContext *cx, CodeGenerator *cg, SrcNoteType type)
{
intN index, n;
jssrcnote *sn;
@ -7512,7 +7493,7 @@ NewSrcNote(JSContext *cx, CodeGenerator *cg, SrcNoteType type)
}
intN
NewSrcNote2(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset)
frontend::NewSrcNote2(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset)
{
intN index;
@ -7525,7 +7506,7 @@ NewSrcNote2(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset
}
intN
NewSrcNote3(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset1,
frontend::NewSrcNote3(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset1,
ptrdiff_t offset2)
{
intN index;
@ -7555,7 +7536,7 @@ GrowSrcNotes(JSContext *cx, CodeGenerator *cg)
}
jssrcnote *
AddToSrcNoteDelta(JSContext *cx, CodeGenerator *cg, jssrcnote *sn, ptrdiff_t delta)
frontend::AddToSrcNoteDelta(JSContext *cx, CodeGenerator *cg, jssrcnote *sn, ptrdiff_t delta)
{
ptrdiff_t base, limit, newdelta, diff;
intN index;
@ -7588,7 +7569,7 @@ AddToSrcNoteDelta(JSContext *cx, CodeGenerator *cg, jssrcnote *sn, ptrdiff_t del
return sn;
}
JSBool
static JSBool
SetSrcNoteOffset(JSContext *cx, CodeGenerator *cg, uintN index, uintN which, ptrdiff_t offset)
{
jssrcnote *sn;
@ -7647,7 +7628,8 @@ SetSrcNoteOffset(JSContext *cx, CodeGenerator *cg, uintN index, uintN which, ptr
#define NBINS 10
static uint32 hist[NBINS];
static void DumpSrcNoteSizeHist()
static void
DumpSrcNoteSizeHist()
{
static FILE *fp;
int i, n;
@ -7677,7 +7659,7 @@ static void DumpSrcNoteSizeHist()
* CORRESPONDING CHANGES!
*/
JSBool
FinishTakingSrcNotes(JSContext *cx, CodeGenerator *cg, jssrcnote *notes)
frontend::FinishTakingSrcNotes(JSContext *cx, CodeGenerator *cg, jssrcnote *notes)
{
uintN prologCount, mainCount, totalCount;
ptrdiff_t offset, delta;
@ -7758,7 +7740,7 @@ NewTryNote(JSContext *cx, CodeGenerator *cg, JSTryNoteKind kind, uintN stackDept
}
void
FinishTakingTryNotes(CodeGenerator *cg, JSTryNoteArray *array)
frontend::FinishTakingTryNotes(CodeGenerator *cg, JSTryNoteArray *array)
{
TryNode *tryNode;
JSTryNote *tn;
@ -7772,8 +7754,6 @@ FinishTakingTryNotes(CodeGenerator *cg, JSTryNoteArray *array)
JS_ASSERT(tn == array->vector);
}
} /* namespace frontend */
/*
* Find the index of the given object for code generator.
*
@ -7852,8 +7832,6 @@ GCConstList::finish(JSConstArray *array)
*dst = *src;
}
} /* namespace js */
/*
* We should try to get rid of offsetBias (always 0 or 1, where 1 is
* JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL.

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

@ -275,7 +275,7 @@ struct StmtInfo {
/*
* The caller is JS_Compile*Script*.
*/
#define TCF_NEED_SCRIPT_OBJECT 0x40000000
#define TCF_NEED_SCRIPT_GLOBAL 0x40000000
/*
* Flags to check for return; vs. return expr; in a function.
@ -1077,9 +1077,6 @@ NewSrcNote3(JSContext *cx, CodeGenerator *cg, SrcNoteType type, ptrdiff_t offset
jssrcnote *
AddToSrcNoteDelta(JSContext *cx, CodeGenerator *cg, jssrcnote *sn, ptrdiff_t delta);
JSBool
SetSrcNoteOffset(JSContext *cx, CodeGenerator *cg, uintN index, uintN which, ptrdiff_t offset);
/*
* Finish taking source notes in cx's notePool, copying final notes to the new
* stable store allocated by the caller and passed in via notes. Return false

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

@ -434,10 +434,8 @@ Boolish(ParseNode *pn)
}
}
namespace js {
bool
FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
{
ParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;
@ -908,5 +906,3 @@ FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
return true;
}
} /* namespace js */

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

@ -56,8 +56,6 @@ JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses));
#undef pn_offsetof
namespace js {
void
ParseNode::become(ParseNode *pn2)
{
@ -465,14 +463,10 @@ NameNode::create(JSAtom *atom, TreeContext *tc)
return (NameNode *)pn;
}
} /* namespace js */
const char js_argument_str[] = "argument";
const char js_variable_str[] = "variable";
const char js_unknown_str[] = "unknown";
namespace js {
const char *
Definition::kindString(Kind kind)
{
@ -602,7 +596,7 @@ CloneParseTree(ParseNode *opn, TreeContext *tc)
* the original tree.
*/
ParseNode *
CloneLeftHandSide(ParseNode *opn, TreeContext *tc)
js::CloneLeftHandSide(ParseNode *opn, TreeContext *tc)
{
ParseNode *pn = tc->parser->new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
opn->pn_pos);
@ -670,5 +664,3 @@ CloneLeftHandSide(ParseNode *opn, TreeContext *tc)
}
return pn;
}
} /* namespace js */

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

@ -586,8 +586,6 @@ ReportBadParameter(JSContext *cx, TreeContext *tc, JSAtom *name, uintN errorNumb
ReportStrictModeError(cx, TS(tc->parser), tc, dn, errorNumber, bytes.ptr());
}
namespace js {
/*
* In strict mode code, all parameter names must be distinct, must not be
* strict mode reserved keywords, and must not be 'eval' or 'arguments'. We
@ -595,7 +593,7 @@ namespace js {
* function's body may turn on strict mode for the function head.
*/
bool
CheckStrictParameters(JSContext *cx, TreeContext *tc)
js::CheckStrictParameters(JSContext *cx, TreeContext *tc)
{
JS_ASSERT(tc->inFunction());
@ -649,8 +647,6 @@ CheckStrictParameters(JSContext *cx, TreeContext *tc)
return true;
}
} /* namespace js */
ParseNode *
Parser::functionBody()
{
@ -865,10 +861,8 @@ MakeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom, TreeContext *tc)
return dn;
}
namespace js {
bool
DefineArg(ParseNode *pn, JSAtom *atom, uintN i, TreeContext *tc)
js::DefineArg(ParseNode *pn, JSAtom *atom, uintN i, TreeContext *tc)
{
ParseNode *argpn, *argsbody;
@ -909,8 +903,6 @@ DefineArg(ParseNode *pn, JSAtom *atom, uintN i, TreeContext *tc)
return true;
}
} /* namespace js */
/*
* Parameter block types for the several Binder functions. We use a common
* helper function signature in order to share code among destructuring and
@ -7287,7 +7279,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
pn3 = NullaryNode::create(tc);
if (!pn3)
return NULL;
pn3->pn_dval = tokenStream.currentToken().t_dval;
pn3->pn_dval = tokenStream.currentToken().number();
if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom))
return NULL;
break;
@ -7313,7 +7305,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
pn3 = NullaryNode::create(tc);
if (!pn3)
return NULL;
pn3->pn_dval = tokenStream.currentToken().t_dval;
pn3->pn_dval = tokenStream.currentToken().number();
if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom))
return NULL;
} else {
@ -7459,7 +7451,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
pn = UnaryNode::create(tc);
if (!pn)
return NULL;
pn->pn_num = (jsint) tokenStream.currentToken().t_dval;
pn->pn_num = tokenStream.currentToken().sharpNumber();
tt = tokenStream.getToken(TSF_OPERAND);
pn->pn_kid = primaryExpr(tt, JS_FALSE);
if (!pn->pn_kid)
@ -7483,7 +7475,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
return NULL;
if (!tc->ensureSharpSlots())
return NULL;
pn->pn_num = (jsint) tokenStream.currentToken().t_dval;
pn->pn_num = tokenStream.currentToken().sharpNumber();
break;
#endif /* JS_HAS_SHARP_VARS */
@ -7687,7 +7679,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
const jschar *chars = tokenStream.getTokenbuf().begin();
size_t length = tokenStream.getTokenbuf().length();
RegExpFlag flags = RegExpFlag(tokenStream.currentToken().t_reflags);
RegExpFlag flags = tokenStream.currentToken().regExpFlags();
RegExpStatics *res = context->regExpStatics();
RegExpObject *reobj;
@ -7717,7 +7709,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
if (!pn)
return NULL;
pn->setOp(JSOP_DOUBLE);
pn->pn_dval = tokenStream.currentToken().t_dval;
pn->pn_dval = tokenStream.currentToken().number();
break;
case TOK_PRIMARY:

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

@ -91,10 +91,8 @@ static const KeywordInfo keywords[] = {
#undef JS_KEYWORD
};
namespace js {
const KeywordInfo *
FindKeyword(const jschar *s, size_t length)
js::FindKeyword(const jschar *s, size_t length)
{
JS_ASSERT(length != 0);
@ -131,7 +129,7 @@ FindKeyword(const jschar *s, size_t length)
}
JSBool
IsIdentifier(JSLinearString *str)
js::IsIdentifier(JSLinearString *str)
{
const jschar *chars = str->chars();
size_t length = str->length();
@ -548,8 +546,8 @@ TokenStream::reportCompileErrorNumberVA(ParseNode *pn, uintN flags, uintN errorN
}
bool
ReportStrictModeError(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn,
uintN errorNumber, ...)
js::ReportStrictModeError(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn,
uintN errorNumber, ...)
{
JS_ASSERT(ts || tc);
JS_ASSERT(cx == ts->getContext());
@ -573,8 +571,8 @@ ReportStrictModeError(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode
}
bool
ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, ParseNode *pn, uintN flags,
uintN errorNumber, ...)
js::ReportCompileErrorNumber(JSContext *cx, TokenStream *ts, ParseNode *pn, uintN flags,
uintN errorNumber, ...)
{
va_list ap;
@ -1715,7 +1713,7 @@ TokenStream::getTokenInternal()
if (!js_strtod(cx, numStart, userbuf.addressOfNextRawChar(), &dummy, &dval))
goto error;
}
tp->t_dval = dval;
tp->setNumber(dval);
tt = TOK_NUMBER;
goto out;
}
@ -1801,7 +1799,7 @@ TokenStream::getTokenInternal()
const jschar *dummy;
if (!GetPrefixInteger(cx, numStart, userbuf.addressOfNextRawChar(), radix, &dummy, &dval))
goto error;
tp->t_dval = dval;
tp->setNumber(dval);
tt = TOK_NUMBER;
goto out;
}
@ -1962,10 +1960,9 @@ TokenStream::getTokenInternal()
* Look for a regexp.
*/
if (flags & TSF_OPERAND) {
uintN reflags, length;
JSBool inCharClass = JS_FALSE;
tokenbuf.clear();
bool inCharClass = false;
for (;;) {
c = getChar();
if (c == '\\') {
@ -1973,9 +1970,9 @@ TokenStream::getTokenInternal()
goto error;
c = getChar();
} else if (c == '[') {
inCharClass = JS_TRUE;
inCharClass = true;
} else if (c == ']') {
inCharClass = JS_FALSE;
inCharClass = false;
} else if (c == '/' && !inCharClass) {
/* For compat with IE, allow unescaped / in char classes. */
break;
@ -1989,31 +1986,36 @@ TokenStream::getTokenInternal()
if (!tokenbuf.append(c))
goto error;
}
for (reflags = 0, length = tokenbuf.length() + 1; ; length++) {
RegExpFlag reflags = NoFlags;
uintN length = tokenbuf.length() + 1;
while (true) {
c = peekChar();
if (c == 'g' && !(reflags & JSREG_GLOB))
reflags |= JSREG_GLOB;
if (c == 'g' && !(reflags & GlobalFlag))
reflags = RegExpFlag(reflags | GlobalFlag);
else if (c == 'i' && !(reflags & IgnoreCaseFlag))
reflags |= IgnoreCaseFlag;
reflags = RegExpFlag(reflags | IgnoreCaseFlag);
else if (c == 'm' && !(reflags & MultilineFlag))
reflags |= MultilineFlag;
reflags = RegExpFlag(reflags | MultilineFlag);
else if (c == 'y' && !(reflags & StickyFlag))
reflags |= StickyFlag;
reflags = RegExpFlag(reflags | StickyFlag);
else
break;
getChar();
length++;
}
c = peekChar();
if (JS7_ISLET(c)) {
char buf[2] = { '\0' };
char buf[2] = { '\0', '\0' };
tp->pos.begin.index += length + 1;
buf[0] = (char)c;
buf[0] = char(c);
ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR, JSMSG_BAD_REGEXP_FLAG,
buf);
(void) getChar();
goto error;
}
tp->t_reflags = reflags;
tp->setRegExpFlags(reflags);
tt = TOK_REGEXP;
break;
}
@ -2069,9 +2071,8 @@ TokenStream::getTokenInternal()
goto error;
}
}
tp->t_dval = (jsdouble) n;
if (cx->hasStrictOption() &&
(c == '=' || c == '#')) {
tp->setSharpNumber(uint16(n));
if (cx->hasStrictOption() && (c == '=' || c == '#')) {
char buf[20];
JS_snprintf(buf, sizeof buf, "#%u%c", n, c);
if (!ReportCompileErrorNumber(cx, this, NULL, JSREPORT_WARNING | JSREPORT_STRICT,
@ -2128,8 +2129,6 @@ TokenStream::getTokenInternal()
return TOK_ERROR;
}
} /* namespace js */
JS_FRIEND_API(int)
js_fgets(char *buf, int size, FILE *file)
{

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

@ -265,18 +265,26 @@ struct Token {
JSAtom *atom; /* potentially-numeric atom */
} n;
} s;
uintN reflags; /* regexp flags, use tokenbuf to access
regexp chars */
class { /* pair for <?target data?> XML PI */
friend struct Token;
private:
friend struct Token;
struct { /* pair for <?target data?> XML PI */
JSAtom *data; /* auxiliary atom table entry */
PropertyName *target; /* main atom table entry */
} xmlpi;
jsdouble dval; /* floating point number */
uint16 sharpNumber; /* sharp variable number: #1# or #1= */
jsdouble number; /* floating point number */
RegExpFlag reflags; /* regexp flags, use tokenbuf to access
regexp chars */
} u;
/* Mutators */
/*
* FIXME: Init type early enough such that all mutators can assert
* type-safety. See bug 697000.
*/
void setName(JSOp op, PropertyName *name) {
JS_ASSERT(op == JSOP_NAME);
u.s.op = op;
@ -294,6 +302,19 @@ struct Token {
u.xmlpi.data = data;
}
void setRegExpFlags(js::RegExpFlag flags) {
JS_ASSERT((flags & AllFlags) == flags);
u.reflags = flags;
}
void setSharpNumber(uint16 sharpNum) {
u.sharpNumber = sharpNum;
}
void setNumber(jsdouble n) {
u.number = n;
}
/* Type-safe accessors */
PropertyName *name() const {
@ -320,11 +341,25 @@ struct Token {
JS_ASSERT(type == TOK_XMLPI);
return u.xmlpi.data;
}
js::RegExpFlag regExpFlags() const {
JS_ASSERT(type == TOK_REGEXP);
JS_ASSERT((u.reflags & AllFlags) == u.reflags);
return u.reflags;
}
uint16 sharpNumber() const {
JS_ASSERT(type == TOK_DEFSHARP || type == TOK_USESHARP);
return u.sharpNumber;
}
jsdouble number() const {
JS_ASSERT(type == TOK_NUMBER);
return u.number;
}
};
#define t_op u.s.op
#define t_reflags u.reflags
#define t_dval u.dval
enum TokenStreamFlags
{

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

@ -59,6 +59,10 @@
useable. See jstypes.h and jsstdint.h. */
#undef JS_HAVE_STDINT_H
/* Define to 1 if the <endian.h> header is present and
useable. See jscpucfg.h. */
#undef JS_HAVE_ENDIAN_H
/* Define to 1 if the <sys/types.h> defines int8_t, etc. */
#undef JS_SYS_TYPES_H_DEFINES_EXACT_SIZE_TYPES

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

@ -370,3 +370,4 @@ MSG_DEF(JSMSG_DEBUG_BAD_LINE, 283, 0, JSEXN_TYPEERR, "invalid line numbe
MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGING, 284, 0, JSEXN_ERR, "can't set breakpoint: script global is not a debuggee")
MSG_DEF(JSMSG_DEBUG_COMPARTMENT_MISMATCH, 285, 2, JSEXN_TYPEERR, "{0}: descriptor .{1} property is an object in a different compartment than the target object")
MSG_DEF(JSMSG_DEBUG_NOT_SCRIPT_FRAME, 286, 0, JSEXN_ERR, "stack frame is not running JavaScript code")
MSG_DEF(JSMSG_CANT_WATCH_PROP, 287, 0, JSEXN_TYPEERR, "properties whose names are objects can't be watched")

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

@ -1278,30 +1278,33 @@ JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
return reinterpret_cast<JSCrossCompartmentCall *>(call);
}
namespace js {
// Declared in jscompartment.h
JSClass js_dummy_class = {
Class dummy_class = {
"jdummy",
JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, NULL,
JSCLASS_NO_OPTIONAL_MEMBERS
JS_ConvertStub
};
} /*namespace js */
JS_PUBLIC_API(JSCrossCompartmentCall *)
JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
{
CHECK_REQUEST(cx);
JSObject *scriptObject = target->u.object;
if (!scriptObject) {
JS_ASSERT(!target->isCachedEval);
GlobalObject *global = target->u.globalObject;
if (!global) {
SwitchToCompartment sc(cx, target->compartment());
scriptObject = JS_NewGlobalObject(cx, &js_dummy_class);
if (!scriptObject)
global = GlobalObject::create(cx, &dummy_class);
if (!global)
return NULL;
}
return JS_EnterCrossCompartmentCall(cx, scriptObject);
return JS_EnterCrossCompartmentCall(cx, global);
}
JS_PUBLIC_API(JSCrossCompartmentCall *)
@ -4582,7 +4585,7 @@ CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, JSPrincipals *p
assertSameCompartment(cx, obj, principals);
AutoLastFrameCheck lfc(cx);
uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_OBJECT;
uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_GLOBAL;
return BytecodeCompiler::compileScript(cx, obj, NULL, principals, tcflags, chars, length,
filename, lineno, version);
}
@ -4759,7 +4762,7 @@ CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals,
JS_ASSERT(i <= len);
len = i;
uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_OBJECT;
uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_GLOBAL;
script = BytecodeCompiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len,
filename, 1, cx->findVersion());
cx->free_(buf);
@ -4820,11 +4823,12 @@ JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *f
}
JS_PUBLIC_API(JSObject *)
JS_GetObjectFromScript(JSScript *script)
JS_GetGlobalFromScript(JSScript *script)
{
JS_ASSERT(script->u.object);
JS_ASSERT(!script->isCachedEval);
JS_ASSERT(script->u.globalObject);
return script->u.object;
return script->u.globalObject;
}
static JSFunction *
@ -5018,7 +5022,7 @@ EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj,
{
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
uint32 flags = TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_OBJECT;
uint32 flags = TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_GLOBAL;
if (!rval)
flags |= TCF_NO_SCRIPT_RVAL;

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

@ -3817,7 +3817,7 @@ JS_CompileFileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj,
JSVersion version);
extern JS_PUBLIC_API(JSObject *)
JS_GetObjectFromScript(JSScript *script);
JS_GetGlobalFromScript(JSScript *script);
extern JS_PUBLIC_API(JSFunction *)
JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,

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

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

@ -208,8 +208,8 @@ class CompartmentChecker
void check(JSScript *script) {
if (script) {
check(script->compartment());
if (script->u.object)
check(script->u.object);
if (!script->isCachedEval && script->u.globalObject)
check(script->u.globalObject);
}
}

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

@ -278,7 +278,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
if (vp->isObject()) {
JSObject *obj = &vp->toObject();
JS_ASSERT(obj->isCrossCompartmentWrapper());
if (global->getJSClass() != &js_dummy_class && obj->getParent() != global) {
if (global->getClass() != &dummy_class && obj->getParent() != global) {
do {
obj->setParent(global);
obj = obj->getProto();
@ -412,42 +412,6 @@ JSCompartment::wrap(JSContext *cx, AutoIdVector &props)
return true;
}
#if defined JS_METHODJIT && defined JS_MONOIC
/*
* Check if the pool containing the code for jit should be destroyed, per the
* heuristics in JSCompartment::sweep.
*/
static inline bool
ScriptPoolDestroyed(JSContext *cx, mjit::JITScript *jit,
uint32 releaseInterval, uint32 &counter)
{
JSC::ExecutablePool *pool = jit->code.m_executablePool;
if (pool->m_gcNumber != cx->runtime->gcNumber) {
/*
* The m_destroy flag may have been set in a previous GC for a pool which had
* references we did not remove (e.g. from the compartment's ExecutableAllocator)
* and is still around. Forget we tried to destroy it in such cases.
*/
pool->m_destroy = false;
pool->m_gcNumber = cx->runtime->gcNumber;
if (--counter == 0) {
pool->m_destroy = true;
counter = releaseInterval;
}
}
return pool->m_destroy;
}
static inline void
ScriptTryDestroyCode(JSContext *cx, JSScript *script, bool normal,
uint32 releaseInterval, uint32 &counter)
{
mjit::JITScript *jit = normal ? script->jitNormal : script->jitCtor;
if (jit && ScriptPoolDestroyed(cx, jit, releaseInterval, counter))
mjit::ReleaseScriptCode(cx, script, !normal);
}
#endif // JS_METHODJIT && JS_MONOIC
/*
* This method marks pointers that cross compartment boundaries. It should be
* called only for per-compartment GCs, since full GCs naturally follow pointers
@ -492,7 +456,7 @@ JSCompartment::markTypes(JSTracer *trc)
}
void
JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
JSCompartment::sweep(JSContext *cx, bool releaseTypes)
{
/* Remove dead wrappers from the table. */
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
@ -531,83 +495,27 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
traceMonitor()->sweep(cx);
#endif
/*
* Kick all frames on the stack into the interpreter, and release all JIT
* code in the compartment.
*/
#ifdef JS_METHODJIT
/*
* Purge PICs in the compartment, along with native call stubs for
* compartments which do not have such stubs on the stack. PICs can
* reference shapes and type data, and native call stubs are disassociated
* from the PIC or MIC they were generated for.
*/
bool canPurgeNativeCalls = true;
VMFrame *f = hasJaegerCompartment() ? jaegerCompartment()->activeFrame() : NULL;
for (; f; f = f->previous) {
if (f->stubRejoin)
canPurgeNativeCalls = false;
}
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
if (script->hasJITCode()) {
#ifdef JS_POLYIC
mjit::ic::PurgePICs(cx, script);
#endif
if (canPurgeNativeCalls) {
if (script->jitNormal)
script->jitNormal->purgeNativeCallStubs();
if (script->jitCtor)
script->jitCtor->purgeNativeCallStubs();
}
}
}
#endif
bool discardScripts = !active && (releaseInterval != 0 || hasDebugModeCodeToDrop);
#if defined JS_METHODJIT && defined JS_MONOIC
/*
* The release interval is the frequency with which we should try to destroy
* executable pools by releasing all JIT code in them, zero to never destroy pools.
* Initialize counter so that the first pool will be destroyed, and eventually drive
* the amount of JIT code in never-used compartments to zero. Don't discard anything
* for compartments which currently have active stack frames.
*/
uint32 counter = 1;
if (discardScripts)
hasDebugModeCodeToDrop = false;
mjit::ClearAllFrames(this);
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
if (script->hasJITCode()) {
mjit::ic::SweepCallICs(cx, script, discardScripts);
if (discardScripts) {
ScriptTryDestroyCode(cx, script, true, releaseInterval, counter);
ScriptTryDestroyCode(cx, script, false, releaseInterval, counter);
}
}
}
mjit::ReleaseScriptCode(cx, script);
#endif
#ifdef JS_METHODJIT
if (types.inferenceEnabled)
mjit::ClearAllFrames(this);
#endif
if (activeAnalysis) {
/*
* Analysis information is in use, so don't clear the analysis pool.
* jitcode still needs to be released, if this is a shape-regenerating
* GC then shape numbers baked into the code may change.
* Use counts for scripts are reset on GC. After discarding code we
* need to let it warm back up to get information like which opcodes
* are setting array holes or accessing getter properties.
*/
#ifdef JS_METHODJIT
if (types.inferenceEnabled) {
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
mjit::ReleaseScriptCode(cx, script);
}
}
script->resetUseCount();
}
#endif
} else {
if (!activeAnalysis) {
/*
* Clear the analysis pool, but don't release its data yet. While
* sweeping types any live data will be allocated into the pool.
@ -615,6 +523,13 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
LifoAlloc oldAlloc(typeLifoAlloc.defaultChunkSize());
oldAlloc.steal(&typeLifoAlloc);
/*
* Periodically release observed types for all scripts. This is safe to
* do when there are no frames for the compartment on the stack.
*/
if (active)
releaseTypes = false;
/*
* Sweep analysis information and everything depending on it from the
* compartment, including all remaining mjit code if inference is
@ -626,12 +541,7 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
if (script->types) {
types::TypeScript::Sweep(cx, script);
/*
* On each 1/8 lifetime, release observed types for all scripts.
* This is always safe to do when there are no frames for the
* compartment on the stack.
*/
if (discardScripts) {
if (releaseTypes) {
script->types->destroy();
script->types = NULL;
script->typesPurged = true;
@ -684,20 +594,6 @@ JSCompartment::purge(JSContext *cx)
if (hasTraceMonitor())
traceMonitor()->needFlush = JS_TRUE;
#endif
#if defined JS_METHODJIT && defined JS_MONOIC
/*
* MICs do not refer to data which can be GC'ed and do not generate stubs
* which might need to be discarded, but are sensitive to shape regeneration.
*/
if (cx->runtime->gcRegenShapes) {
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
if (script->hasJITCode())
mjit::ic::PurgeMICs(cx, script);
}
}
#endif
}
MathCache *
@ -861,14 +757,11 @@ JSCompartment::getBreakpointSite(jsbytecode *pc)
}
BreakpointSite *
JSCompartment::getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc, JSObject *scriptObject)
JSCompartment::getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc,
GlobalObject *scriptGlobal)
{
JS_ASSERT(script->code <= pc);
JS_ASSERT(pc < script->code + script->length);
JS_ASSERT_IF(scriptObject, scriptObject->isScript() || scriptObject->isFunction());
JS_ASSERT_IF(scriptObject && scriptObject->isFunction(),
scriptObject->getFunctionPrivate()->script() == script);
JS_ASSERT_IF(scriptObject && scriptObject->isScript(), scriptObject->getScript() == script);
BreakpointSiteMap::AddPtr p = breakpointSites.lookupForAdd(pc);
if (!p) {
@ -880,10 +773,10 @@ JSCompartment::getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbyte
}
BreakpointSite *site = p->value;
if (site->scriptObject)
JS_ASSERT_IF(scriptObject, site->scriptObject == scriptObject);
if (site->scriptGlobal)
JS_ASSERT_IF(scriptGlobal, site->scriptGlobal == scriptGlobal);
else
site->scriptObject = scriptObject;
site->scriptGlobal = scriptGlobal;
return site;
}

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

@ -293,10 +293,11 @@ struct TraceMonitor {
namespace mjit {
class JaegerCompartment;
}
}
/* Defined in jsapi.cpp */
extern JSClass js_dummy_class;
extern Class dummy_class;
} /* namespace js */
#ifndef JS_EVAL_CACHE_SHIFT
# define JS_EVAL_CACHE_SHIFT 6
@ -533,7 +534,7 @@ struct JS_FRIEND_API(JSCompartment) {
bool wrap(JSContext *cx, js::AutoIdVector &props);
void markTypes(JSTracer *trc);
void sweep(JSContext *cx, uint32 releaseInterval);
void sweep(JSContext *cx, bool releaseTypes);
void purge(JSContext *cx);
void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
@ -615,7 +616,7 @@ struct JS_FRIEND_API(JSCompartment) {
js::BreakpointSite *getBreakpointSite(jsbytecode *pc);
js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc,
JSObject *scriptObject);
js::GlobalObject *scriptGlobal);
void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSScript *script, JSObject *handler);
void clearTraps(JSContext *cx, JSScript *script);
bool markTrapClosuresIteratively(JSTracer *trc);

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

@ -1,182 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* Generate CPU-specific bit-size and similar #defines.
*/
#include <stdio.h>
#include <stdlib.h>
#if defined(CROSS_COMPILE) && !defined(FORCE_BIG_ENDIAN) && !defined(FORCE_LITTLE_ENDIAN)
#include <prtypes.h>
#endif
/************************************************************************/
int main(int argc, char **argv)
{
printf("#ifndef js_cpucfg___\n");
printf("#define js_cpucfg___\n\n");
printf("/* AUTOMATICALLY GENERATED - DO NOT EDIT */\n\n");
#ifdef CROSS_COMPILE
#if defined(__APPLE__) && !defined(FORCE_BIG_ENDIAN) && !defined(FORCE_LITTLE_ENDIAN)
/*
* Darwin NSPR uses the same MDCPUCFG (_darwin.cfg) for multiple
* processors, and determines which processor to configure for based
* on compiler predefined macros. We do the same thing here.
*/
printf("#ifdef __LITTLE_ENDIAN__\n");
printf("#define IS_LITTLE_ENDIAN 1\n");
printf("#undef IS_BIG_ENDIAN\n");
printf("#else\n");
printf("#undef IS_LITTLE_ENDIAN\n");
printf("#define IS_BIG_ENDIAN 1\n");
printf("#endif\n\n");
#elif defined(IS_LITTLE_ENDIAN) || defined(FORCE_LITTLE_ENDIAN)
printf("#define IS_LITTLE_ENDIAN 1\n");
printf("#undef IS_BIG_ENDIAN\n\n");
#elif defined(IS_BIG_ENDIAN) || defined(FORCE_BIG_ENDIAN)
printf("#undef IS_LITTLE_ENDIAN\n");
printf("#define IS_BIG_ENDIAN 1\n\n");
#else
#error "Endianess not defined."
#endif
#else
/*
* We don't handle PDP-endian or similar orders: if a short is big-endian,
* so must int and long be big-endian for us to generate the IS_BIG_ENDIAN
* #define and the IS_LITTLE_ENDIAN #undef.
*/
{
int big_endian = 0, little_endian = 0, ntests = 0;
if (sizeof(short) == 2) {
/* force |volatile| here to get rid of any compiler optimisations
* (var in register etc.) which may be appiled to |auto| vars -
* even those in |union|s...
* (|static| is used to get the same functionality for compilers
* which do not honor |volatile|...).
*/
volatile static union {
short i;
char c[2];
} u;
u.i = 0x0102;
big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02);
little_endian += (u.c[0] == 0x02 && u.c[1] == 0x01);
ntests++;
}
if (sizeof(int) == 4) {
/* force |volatile| here ... */
volatile static union {
int i;
char c[4];
} u;
u.i = 0x01020304;
big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02 &&
u.c[2] == 0x03 && u.c[3] == 0x04);
little_endian += (u.c[0] == 0x04 && u.c[1] == 0x03 &&
u.c[2] == 0x02 && u.c[3] == 0x01);
ntests++;
}
if (sizeof(long) == 8) {
/* force |volatile| here ... */
volatile static union {
long i;
char c[8];
} u;
/*
* Write this as portably as possible: avoid 0x0102030405060708L
* and <<= 32.
*/
u.i = 0x01020304;
u.i <<= 16, u.i <<= 16;
u.i |= 0x05060708;
big_endian += (u.c[0] == 0x01 && u.c[1] == 0x02 &&
u.c[2] == 0x03 && u.c[3] == 0x04 &&
u.c[4] == 0x05 && u.c[5] == 0x06 &&
u.c[6] == 0x07 && u.c[7] == 0x08);
little_endian += (u.c[0] == 0x08 && u.c[1] == 0x07 &&
u.c[2] == 0x06 && u.c[3] == 0x05 &&
u.c[4] == 0x04 && u.c[5] == 0x03 &&
u.c[6] == 0x02 && u.c[7] == 0x01);
ntests++;
}
if (big_endian && big_endian == ntests) {
printf("#undef IS_LITTLE_ENDIAN\n");
printf("#define IS_BIG_ENDIAN 1\n\n");
} else if (little_endian && little_endian == ntests) {
printf("#define IS_LITTLE_ENDIAN 1\n");
printf("#undef IS_BIG_ENDIAN\n\n");
} else {
fprintf(stderr, "%s: unknown byte order"
"(big_endian=%d, little_endian=%d, ntests=%d)!\n",
argv[0], big_endian, little_endian, ntests);
return EXIT_FAILURE;
}
}
#endif /* CROSS_COMPILE */
// PA-RISC is the only platform we try to support on which the stack
// grows towards higher addresses. Trying to detect it here has
// historically led to portability problems, which aren't worth it
// given the near consensus on stack growth direction.
printf("#ifdef __hppa\n"
"# define JS_STACK_GROWTH_DIRECTION (1)\n"
"#else\n"
"# define JS_STACK_GROWTH_DIRECTION (-1)\n"
"#endif\n");
printf("#endif /* js_cpucfg___ */\n");
return EXIT_SUCCESS;
}

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

@ -68,16 +68,40 @@
#define JS_BITS_PER_WORD_LOG2 5
#define JS_ALIGN_OF_POINTER 4L
#else
#elif defined(__APPLE__)
#if __LITTLE_ENDIAN__
#define IS_LITTLE_ENDIAN 1
#undef IS_BIG_ENDIAN
#elif __BIG_ENDIAN__
#undef IS_LITTLE_ENDIAN
#define IS_BIG_ENDIAN 1
#endif
#error "This file is supposed to be auto-generated on most platforms, but the"
#error "static version for Windows and OS2 platforms is being used."
#error "Something's probably wrong with paths/headers/dependencies/Makefiles."
#elif defined(JS_HAVE_ENDIAN_H)
#include <endian.h>
#if defined(__BYTE_ORDER)
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define IS_LITTLE_ENDIAN 1
#undef IS_BIG_ENDIAN
#elif __BYTE_ORDER == __BIG_ENDIAN
#undef IS_LITTLE_ENDIAN
#define IS_BIG_ENDIAN 1
#endif
#else /* !defined(__BYTE_ORDER) */
#error "endian.h does not define __BYTE_ORDER. Cannot determine endianness."
#endif
#else /* !defined(HAVE_ENDIAN_H) */
#error "Cannot determine endianness of your platform. Please add support to jscpucfg.h."
#endif
#ifndef JS_STACK_GROWTH_DIRECTION
#define JS_STACK_GROWTH_DIRECTION (-1)
#ifdef __hppa
# define JS_STACK_GROWTH_DIRECTION (1)
#else
# define JS_STACK_GROWTH_DIRECTION (-1)
#endif
#endif
#endif /* js_cpucfg___ */

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

@ -297,6 +297,9 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
AutoValueRooter idroot(cx);
if (JSID_IS_INT(id)) {
propid = id;
} else if (JSID_IS_OBJECT(id)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH_PROP);
return false;
} else {
if (!js_ValueToStringId(cx, IdToValue(id), &propid))
return false;
@ -328,7 +331,7 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
}
cx->compartment->watchpointMap = wpmap;
}
return wpmap->watch(cx, obj, id, handler, closure);
return wpmap->watch(cx, obj, propid, handler, closure);
}
JS_PUBLIC_API(JSBool)
@ -1046,9 +1049,6 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
JSPrincipals *principals;
nbytes = sizeof *script;
if (script->u.object)
nbytes += JS_GetObjectTotalSize(cx, script->u.object);
nbytes += script->length * sizeof script->code[0];
nbytes += script->natoms * sizeof script->atoms[0];
for (size_t i = 0; i < script->natoms; i++)

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

@ -1558,6 +1558,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
uint32 flagsword; /* word for argument count and fun->flags */
cx = xdr->cx;
JSScript *script;
if (xdr->mode == JSXDR_ENCODE) {
fun = (*objp)->getFunctionPrivate();
if (!fun->isInterpreted()) {
@ -1570,12 +1571,14 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
}
firstword = (fun->u.i.skipmin << 2) | !!fun->atom;
flagsword = (fun->nargs << 16) | fun->flags;
script = fun->script();
} else {
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
if (!fun)
return false;
fun->clearParent();
fun->clearType();
script = NULL;
}
AutoObjectRooter tvr(cx, fun);
@ -1587,28 +1590,20 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
if (!JS_XDRUint32(xdr, &flagsword))
return false;
if (!js_XDRScript(xdr, &script))
return false;
if (xdr->mode == JSXDR_DECODE) {
fun->nargs = flagsword >> 16;
JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
fun->flags = uint16(flagsword);
fun->u.i.skipmin = uint16(firstword >> 2);
}
/*
* Don't directly store into fun->u.i.script because we want this to happen
* at the same time as we set the script's owner.
*/
JSScript *script = fun->script();
if (!js_XDRScript(xdr, &script))
return false;
if (xdr->mode == JSXDR_DECODE) {
*objp = fun;
fun->setScript(script);
if (!fun->script()->typeSetFunction(cx, fun))
if (!script->typeSetFunction(cx, fun))
return false;
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
js_CallNewScriptHook(cx, fun->script(), fun);
*objp = fun;
}
return true;
@ -1674,10 +1669,8 @@ fun_trace(JSTracer *trc, JSObject *obj)
if (fun->atom)
MarkString(trc, fun->atom, "atom");
if (fun->isInterpreted() && fun->script()) {
CheckScriptOwner(fun->script(), obj);
if (fun->isInterpreted() && fun->script())
MarkScript(trc, fun->script(), "script");
}
}
static void
@ -2421,19 +2414,18 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
JS_ASSERT(script);
JS_ASSERT(script->compartment() == fun->compartment());
JS_ASSERT(script->compartment() != cx->compartment);
JS_OPT_ASSERT(script->ownerObject == fun);
cfun->u.i.script_ = NULL;
JSScript *cscript = js_CloneScript(cx, script);
if (!cscript)
return NULL;
cscript->u.globalObject = cfun->getGlobal();
cfun->setScript(cscript);
if (!cfun->script()->typeSetFunction(cx, cfun))
if (!cscript->typeSetFunction(cx, cfun))
return NULL;
js_CallNewScriptHook(cx, cfun->script(), cfun);
Debugger::onNewScript(cx, cfun->script(), cfun, NULL);
Debugger::onNewScript(cx, cfun->script(), NULL);
}
}
return clone;

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

@ -203,10 +203,9 @@ struct JSFunction : public JSObject_Slots2
void setScript(JSScript *script) {
JS_ASSERT(isInterpreted());
u.i.script_ = script;
script->setOwnerObject(this);
}
JSScript * maybeScript() const {
JSScript *maybeScript() const {
return isInterpreted() ? script() : NULL;
}

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

@ -730,12 +730,8 @@ js_GCThingIsMarked(void *thing, uintN color = BLACK)
return reinterpret_cast<Cell *>(thing)->isMarked(color);
}
/*
* 1/8 life for JIT code. After this number of microseconds have passed, 1/8 of all
* JIT code is discarded in inactive compartments, regardless of how often that
* code runs.
*/
static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 60 * 1000 * 1000;
/* Lifetime for type sets attached to scripts containing observed types. */
static const int64 JIT_SCRIPT_RELEASE_TYPES_INTERVAL = 60 * 1000 * 1000;
JSBool
js_InitGC(JSRuntime *rt, uint32 maxbytes)
@ -777,7 +773,7 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
*/
rt->setGCLastBytes(8192, GC_NORMAL);
rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_EIGHTH_LIFETIME;
rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_RELEASE_TYPES_INTERVAL;
return true;
}
@ -2281,27 +2277,19 @@ GCHelperThread::doSweep()
#endif /* JS_THREADSAFE */
static uint32
ComputeJitReleaseInterval(JSContext *cx)
static bool
ReleaseObservedTypes(JSContext *cx)
{
JSRuntime *rt = cx->runtime;
/*
* Figure out how much JIT code should be released from inactive compartments.
* If multiple eighth-lives have passed, compound the release interval linearly;
* if enough time has passed, all inactive JIT code will be released.
*/
uint32 releaseInterval = 0;
bool releaseTypes = false;
int64 now = PRMJ_Now();
if (now >= rt->gcJitReleaseTime) {
releaseInterval = 8;
while (now >= rt->gcJitReleaseTime) {
if (--releaseInterval == 1)
rt->gcJitReleaseTime = now;
rt->gcJitReleaseTime += JIT_SCRIPT_EIGHTH_LIFETIME;
}
releaseTypes = true;
rt->gcJitReleaseTime = now + JIT_SCRIPT_RELEASE_TYPES_INTERVAL;
}
return releaseInterval;
return releaseTypes;
}
static void
@ -2452,9 +2440,9 @@ SweepPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind)
if (!rt->gcCurrentCompartment)
Debugger::sweepAll(cx);
uint32 releaseInterval = rt->gcCurrentCompartment ? 0 : ComputeJitReleaseInterval(cx);
bool releaseTypes = !rt->gcCurrentCompartment && ReleaseObservedTypes(cx);
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->sweep(cx, releaseInterval);
c->sweep(cx, releaseTypes);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_OBJECT);

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

@ -832,8 +832,8 @@ MarkChildren(JSTracer *trc, JSScript *script)
MarkValueRange(trc, constarray->length, constarray->vector, "consts");
}
if (!script->isCachedEval && script->u.object)
MarkObject(trc, *script->u.object, "object");
if (!script->isCachedEval && script->u.globalObject)
MarkObject(trc, *script->u.globalObject, "object");
if (IS_GC_MARKING_TRACER(trc) && script->filename)
js_MarkScriptFilename(script->filename);
@ -842,13 +842,6 @@ MarkChildren(JSTracer *trc, JSScript *script)
if (script->types)
script->types->trace(trc);
#ifdef JS_METHODJIT
if (script->jitNormal)
script->jitNormal->trace(trc);
if (script->jitCtor)
script->jitCtor->trace(trc);
#endif
}
void

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

@ -6086,21 +6086,6 @@ TypeScript::Sweep(JSContext *cx, JSScript *script)
* cannot alias the most recent one, and future activations will overwrite
* activeCall on creation.
*/
/*
* Method JIT code depends on the type inference data which is about to
* be purged, so purge the jitcode as well.
*/
#ifdef JS_METHODJIT
mjit::ReleaseScriptCode(cx, script);
/*
* Use counts for scripts are reset on GC. After discarding code we need to
* let it warm back up to get information like which opcodes are setting
* array holes or accessing getter properties.
*/
script->resetUseCount();
#endif
}
void

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

@ -1802,30 +1802,12 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
goto error; \
JS_END_MACRO
#if defined(JS_TRACER) && defined(JS_METHODJIT)
# define LEAVE_ON_SAFE_POINT() \
do { \
JS_ASSERT_IF(leaveOnSafePoint, !TRACE_RECORDER(cx)); \
JS_ASSERT_IF(leaveOnSafePoint, !TRACE_PROFILER(cx)); \
JS_ASSERT_IF(leaveOnSafePoint, interpMode != JSINTERP_NORMAL); \
if (leaveOnSafePoint && !regs.fp()->hasImacropc() && \
script->maybeNativeCodeForPC(regs.fp()->isConstructing(), regs.pc)) { \
JS_ASSERT(!TRACE_RECORDER(cx)); \
interpReturnOK = true; \
goto leave_on_safe_point; \
} \
} while (0)
#else
# define LEAVE_ON_SAFE_POINT() /* nop */
#endif
#define BRANCH(n) \
JS_BEGIN_MACRO \
regs.pc += (n); \
op = (JSOp) *regs.pc; \
if ((n) <= 0) \
goto check_backedge; \
LEAVE_ON_SAFE_POINT(); \
DO_OP(); \
JS_END_MACRO
@ -1861,13 +1843,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
Value *argv = regs.fp()->maybeFormalArgs();
CHECK_INTERRUPT_HANDLER();
#if defined(JS_TRACER) && defined(JS_METHODJIT)
bool leaveOnSafePoint = (interpMode == JSINTERP_SAFEPOINT);
# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) (leaveOnSafePoint = false))
#else
# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) 0)
#endif
if (!entryFrame)
entryFrame = regs.fp();
@ -2050,17 +2025,8 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
LoopProfile *prof = TRACE_PROFILER(cx);
JS_ASSERT(!TRACE_RECORDER(cx));
LoopProfile::ProfileAction act = prof->profileOperation(cx, op);
switch (act) {
case LoopProfile::ProfComplete:
if (interpMode != JSINTERP_NORMAL) {
leaveOnSafePoint = true;
LEAVE_ON_SAFE_POINT();
}
break;
default:
moreInterrupts = true;
break;
}
if (act != LoopProfile::ProfComplete)
moreInterrupts = true;
}
#endif
if (TraceRecorder* tr = TRACE_RECORDER(cx)) {
@ -2068,23 +2034,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
AbortableRecordingStatus status = tr->monitorRecording(op);
JS_ASSERT_IF(cx->isExceptionPending(), status == ARECORD_ERROR);
if (interpMode != JSINTERP_NORMAL) {
JS_ASSERT(interpMode == JSINTERP_RECORD || JSINTERP_SAFEPOINT);
switch (status) {
case ARECORD_IMACRO_ABORTED:
case ARECORD_ABORTED:
case ARECORD_COMPLETED:
case ARECORD_STOP:
#ifdef JS_METHODJIT
leaveOnSafePoint = true;
LEAVE_ON_SAFE_POINT();
#endif
break;
default:
break;
}
}
switch (status) {
case ARECORD_CONTINUE:
moreInterrupts = true;
@ -2093,7 +2042,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
case ARECORD_IMACRO_ABORTED:
atoms = rt->atomState.commonAtomsStart();
op = JSOp(*regs.pc);
CLEAR_LEAVE_ON_TRACE_POINT();
if (status == ARECORD_IMACRO)
DO_OP(); /* keep interrupting for op. */
break;
@ -2138,7 +2086,7 @@ END_EMPTY_CASES
BEGIN_CASE(JSOP_TRACE)
BEGIN_CASE(JSOP_NOTRACE)
LEAVE_ON_SAFE_POINT();
/* No-op */
END_CASE(JSOP_TRACE)
check_backedge:
@ -2155,7 +2103,6 @@ check_backedge:
JS_ASSERT(!TRACE_PROFILER(cx));
MONITOR_BRANCH_TRACEVIS;
ENABLE_INTERRUPTS();
CLEAR_LEAVE_ON_TRACE_POINT();
}
JS_ASSERT_IF(cx->isExceptionPending(), r == MONITOR_ERROR);
RESTORE_INTERP_VARS_CHECK_EXCEPTION();
@ -2280,7 +2227,6 @@ BEGIN_CASE(JSOP_STOP)
if (js_CodeSpec[*imacpc].format & JOF_DECOMPOSE)
regs.pc += GetDecomposeLength(imacpc, js_CodeSpec[*imacpc].length);
regs.fp()->clearImacropc();
LEAVE_ON_SAFE_POINT();
atoms = script->atoms;
op = JSOp(*regs.pc);
DO_OP();
@ -5349,12 +5295,6 @@ END_VARLEN_CASE
BEGIN_CASE(JSOP_EXCEPTION)
PUSH_COPY(cx->getPendingException());
cx->clearPendingException();
#if defined(JS_TRACER) && defined(JS_METHODJIT)
if (interpMode == JSINTERP_PROFILE) {
leaveOnSafePoint = true;
LEAVE_ON_SAFE_POINT();
}
#endif
CHECK_BRANCH();
END_CASE(JSOP_EXCEPTION)

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

@ -215,10 +215,9 @@ enum InterpMode
{
JSINTERP_NORMAL = 0, /* interpreter is running normally */
JSINTERP_RECORD = 1, /* interpreter has been started to record/run traces */
JSINTERP_SAFEPOINT = 2, /* interpreter should leave on a method JIT safe point */
JSINTERP_PROFILE = 3, /* interpreter should profile a loop */
JSINTERP_REJOIN = 4, /* as normal, but the frame has already started */
JSINTERP_SKIP_TRAP = 5 /* as REJOIN, but skip trap at first opcode */
JSINTERP_PROFILE = 2, /* interpreter should profile a loop */
JSINTERP_REJOIN = 3, /* as normal, but the frame has already started */
JSINTERP_SKIP_TRAP = 4 /* as REJOIN, but skip trap at first opcode */
};
/*

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

@ -1126,7 +1126,6 @@ class EvalScriptGuard
void setNewScript(JSScript *script) {
/* NewScriptFromCG has already called js_CallNewScriptHook. */
JS_ASSERT(!script_ && script);
script->setOwnerObject(JS_CACHED_SCRIPT);
script_ = script;
script_->isActiveEval = true;
}
@ -6751,25 +6750,21 @@ js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
JS_ASSERT(protoKey < JSProto_LIMIT);
if (protoKey != JSProto_Null) {
if (!scopeobj) {
if (cx->hasfp())
scopeobj = &cx->fp()->scopeChain();
if (!scopeobj) {
scopeobj = cx->globalObject;
if (!scopeobj) {
*protop = NULL;
return true;
}
}
}
scopeobj = scopeobj->getGlobal();
if (scopeobj->isGlobal()) {
const Value &v = scopeobj->getReservedSlot(JSProto_LIMIT + protoKey);
if (v.isObject()) {
*protop = &v.toObject();
GlobalObject *global;
if (scopeobj) {
global = scopeobj->getGlobal();
} else {
global = GetCurrentGlobal(cx);
if (!global) {
*protop = NULL;
return true;
}
}
const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey);
if (v.isObject()) {
*protop = &v.toObject();
return true;
}
}
return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp);

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

@ -1184,12 +1184,6 @@ struct JSObject : js::gc::Cell {
inline js::NativeIterator *getNativeIterator() const;
inline void setNativeIterator(js::NativeIterator *);
/*
* Script-related getters.
*/
inline JSScript *getScript() const;
/*
* XML-related getters and setters.
*/
@ -1465,7 +1459,6 @@ struct JSObject : js::gc::Cell {
inline bool isCall() const { return clasp == &js::CallClass; }
inline bool isDeclEnv() const { return clasp == &js::DeclEnvClass; }
inline bool isRegExp() const { return clasp == &js::RegExpClass; }
inline bool isScript() const { return clasp == &js::ScriptClass; }
inline bool isGenerator() const { return clasp == &js::GeneratorClass; }
inline bool isIterator() const { return clasp == &js::IteratorClass; }
inline bool isStopIteration() const { return clasp == &js::StopIterationClass; }

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

@ -1472,6 +1472,13 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *p
return NewNativeClassInstance(cx, clasp, proto, parent, kind);
}
inline GlobalObject *
GetCurrentGlobal(JSContext *cx)
{
JSObject *scopeChain = (cx->hasfp()) ? &cx->fp()->scopeChain() : cx->globalObject;
return scopeChain ? scopeChain->getGlobal() : NULL;
}
bool
FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
Class *clasp);

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

@ -129,10 +129,13 @@ class MatchPairs;
enum RegExpFlag
{
IgnoreCaseFlag = JS_BIT(0),
GlobalFlag = JS_BIT(1),
MultilineFlag = JS_BIT(2),
StickyFlag = JS_BIT(3)
IgnoreCaseFlag = 0x01,
GlobalFlag = 0x02,
MultilineFlag = 0x04,
StickyFlag = 0x08,
NoFlags = 0x00,
AllFlags = 0x0f
};
enum RegExpExecType

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

@ -2354,7 +2354,7 @@ ASTSerializer::comprehension(ParseNode *pn, Value *dst)
return false;
next = next->pn_kid2;
} else if (next->isKind(TOK_LC) && next->pn_count == 0) {
/* js_FoldConstants optimized away the push. */
/* FoldConstants optimized away the push. */
NodeVector empty(cx);
return builder.arrayExpression(empty, &pn->pn_pos, dst);
}

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

@ -306,14 +306,6 @@ CheckScript(JSScript *script, JSScript *prev)
}
}
void
CheckScriptOwner(JSScript *script, JSObject *owner)
{
JS_OPT_ASSERT(script->ownerObject == owner);
if (owner != JS_NEW_SCRIPT && owner != JS_CACHED_SCRIPT)
JS_OPT_ASSERT(script->compartment() == owner->compartment());
}
#endif /* JS_CRASH_DIAGNOSTICS */
} /* namespace js */
@ -756,37 +748,6 @@ JSPCCounters::destroy(JSContext *cx)
}
}
static void
script_trace(JSTracer *trc, JSObject *obj)
{
JSScript *script = (JSScript *) obj->getPrivate();
if (script) {
CheckScriptOwner(script, obj);
MarkScript(trc, script, "script");
}
}
JS_FRIEND_DATA(Class) js::ScriptClass = {
"Script",
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
JS_PropertyStub, /* addProperty */
JS_PropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */
JS_StrictPropertyStub, /* setProperty */
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
NULL, /* finalize */
NULL, /* reserved0 */
NULL, /* checkAccess */
NULL, /* call */
NULL, /* construct */
NULL, /* xdrObject */
NULL, /* hasInstance */
script_trace
};
/*
* Shared script filename management.
*/
@ -965,7 +926,6 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
PodZero(script);
#ifdef JS_CRASH_DIAGNOSTICS
script->cookie1[0] = script->cookie2[0] = JS_SCRIPT_COOKIE;
script->ownerObject = JS_NEW_SCRIPT;
#endif
#if JS_SCRIPT_INLINE_DATA_LIMIT
if (!data)
@ -1241,23 +1201,26 @@ JSScript::NewScriptFromCG(JSContext *cx, CodeGenerator *cg)
return NULL;
fun->setScript(script);
script->u.globalObject = fun->getParent() ? fun->getParent()->getGlobal() : NULL;
} else {
/*
* Initialize script->object, if necessary, so that the debugger has a
* valid holder object.
*/
if ((cg->flags & TCF_NEED_SCRIPT_OBJECT) && !js_NewScriptObject(cx, script))
return NULL;
if (cg->flags & TCF_NEED_SCRIPT_GLOBAL)
script->u.globalObject = GetCurrentGlobal(cx);
}
/* Tell the debugger about this compiled script. */
js_CallNewScriptHook(cx, script, fun);
if (!cg->parent) {
JSObject *owner = fun ? fun : script->u.object;
GlobalObject *compileAndGoGlobal = NULL;
if (script->compileAndGo)
compileAndGoGlobal = (owner ? owner : cg->scopeChain())->getGlobal();
Debugger::onNewScript(cx, script, owner, compileAndGoGlobal);
if (script->compileAndGo) {
compileAndGoGlobal = script->u.globalObject;
if (!compileAndGoGlobal)
compileAndGoGlobal = cg->scopeChain()->getGlobal();
}
Debugger::onNewScript(cx, script, compileAndGoGlobal);
}
return script;
@ -1288,15 +1251,6 @@ JSScript::dataSize(JSUsableSizeFun usf)
return usable ? usable : dataSize();
}
void
JSScript::setOwnerObject(JSObject *owner)
{
#ifdef JS_CRASH_DIAGNOSTICS
CheckScriptOwner(this, JS_NEW_SCRIPT);
ownerObject = owner;
#endif
}
/*
* Nb: srcnotes are variable-length. This function computes the number of
* srcnote *slots*, which may be greater than the number of srcnotes.
@ -1371,27 +1325,6 @@ JSScript::finalize(JSContext *cx)
}
}
JSObject *
js_NewScriptObject(JSContext *cx, JSScript *script)
{
JS_ASSERT(!script->u.object);
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &ScriptClass, NULL, NULL);
if (!obj)
return NULL;
obj->setPrivate(script);
script->u.object = obj;
script->setOwnerObject(obj);
/*
* Clear the object's type/proto, to avoid entraining stuff. Once we no longer use the parent
* for security checks, then we can clear the parent, too.
*/
obj->clearType();
return obj;
}
namespace js {
static const uint32 GSN_CACHE_THRESHOLD = 100;

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

@ -426,9 +426,6 @@ class JSPCCounters {
static const uint32 JS_SCRIPT_COOKIE = 0xc00cee;
static JSObject * const JS_NEW_SCRIPT = (JSObject *)0x12345678;
static JSObject * const JS_CACHED_SCRIPT = (JSObject *)0x12341234;
struct JSScript : public js::gc::Cell {
/*
* Two successively less primitive ways to make a new JSScript. The first
@ -561,19 +558,20 @@ struct JSScript : public js::gc::Cell {
union {
/*
* A script object of class ScriptClass, to ensure the script is GC'd.
* A global object for the script.
* - All scripts returned by JSAPI functions (JS_CompileScript,
* JS_CompileFile, etc.) have these objects.
* - Function scripts never have script objects; such scripts are owned
* by their function objects.
* JS_CompileFile, etc.) have a non-null globalObject.
* - A function script has a globalObject if the function comes from a
* compile-and-go script.
* - Temporary scripts created by obj_eval, JS_EvaluateScript, and
* similar functions never have these objects; such scripts are
* explicitly destroyed by the code that created them.
* similar functions never have the globalObject field set; for such
* scripts the global should be extracted from the JS frame that
* execute scripts.
*/
JSObject *object;
js::GlobalObject *globalObject;
/* Hash table chaining for JSCompartment::evalCache. */
JSScript *evalHashLink;
JSScript *evalHashLink;
} u;
uint32 *closedSlots; /* vector of closed slots; args first, then vars. */
@ -582,14 +580,10 @@ struct JSScript : public js::gc::Cell {
JSPCCounters pcCounters;
#ifdef JS_CRASH_DIAGNOSTICS
JSObject *ownerObject;
/* All diagnostic fields must be multiples of Cell::CellSize. */
uint32 cookie2[sizeof(JSObject *) == 4 ? 1 : 2];
uint32 cookie2[Cell::CellSize / sizeof(uint32)];
#endif
void setOwnerObject(JSObject *owner);
#ifdef DEBUG
/*
* Unique identifier within the compartment for this script, used for
@ -638,6 +632,11 @@ struct JSScript : public js::gc::Cell {
inline void clearNesting();
/* Return creation time global or null. */
js::GlobalObject *getGlobalObjectOrNull() const {
return isCachedEval ? NULL : u.globalObject;
}
private:
bool makeTypes(JSContext *cx, JSFunction *fun);
bool makeAnalysis(JSContext *cx);
@ -685,7 +684,7 @@ struct JSScript : public js::gc::Cell {
/* Size of the JITScript and all sections. (This method is implemented in MethodJIT.h.) */
JS_FRIEND_API(size_t) jitDataSize(JSUsableSizeFun usf);
#endif
jsbytecode *main() {
@ -803,7 +802,7 @@ struct JSScript : public js::gc::Cell {
* count-style interface.)
*/
bool setStepModeFlag(JSContext *cx, bool step);
/*
* Increment or decrement the single-step count. If the count is non-zero or
* the flag (set by setStepModeFlag) is set, then the script is in
@ -848,9 +847,6 @@ StackDepth(JSScript *script)
JS_END_MACRO
extern JSObject *
js_InitScriptClass(JSContext *cx, JSObject *obj);
extern void
js_MarkScriptFilename(const char *filename);
@ -873,19 +869,11 @@ namespace js {
#ifdef JS_CRASH_DIAGNOSTICS
void
CheckScriptOwner(JSScript *script, JSObject *owner);
void
CheckScript(JSScript *script, JSScript *prev);
#else
inline void
CheckScriptOwner(JSScript *script, JSObject *owner)
{
}
inline void
CheckScript(JSScript *script, JSScript *prev)
{
@ -895,9 +883,6 @@ CheckScript(JSScript *script, JSScript *prev)
} /* namespace js */
extern JSObject *
js_NewScriptObject(JSContext *cx, JSScript *script);
/*
* To perturb as little code as possible, we introduce a js_GetSrcNote lookup
* cache without adding an explicit cx parameter. Thus js_GetSrcNote becomes

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

@ -215,11 +215,4 @@ JSScript::clearNesting()
}
}
inline JSScript *
JSObject::getScript() const
{
JS_ASSERT(isScript());
return static_cast<JSScript *>(getPrivate());
}
#endif /* jsscriptinlines_h___ */

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

@ -1319,14 +1319,8 @@ static void
Unblacklist(JSScript *script, jsbytecode *pc)
{
JS_ASSERT(*pc == JSOP_NOTRACE || *pc == JSOP_TRACE);
if (*pc == JSOP_NOTRACE) {
if (*pc == JSOP_NOTRACE)
*pc = JSOP_TRACE;
#ifdef JS_METHODJIT
/* This code takes care of unblacklisting in the method JIT. */
js::mjit::ResetTraceHint(script, pc, GET_UINT16(pc), false);
#endif
}
}
#ifdef JS_METHODJIT
@ -2688,17 +2682,6 @@ TraceMonitor::flush()
flushEpoch++;
#ifdef JS_METHODJIT
if (loopProfiles) {
for (LoopProfileMap::Enum e(*loopProfiles); !e.empty(); e.popFront()) {
jsbytecode *pc = e.front().key;
LoopProfile *prof = e.front().value;
/* This code takes care of resetting all methodjit state. */
js::mjit::ResetTraceHint(prof->entryScript, pc, GET_UINT16(pc), true);
}
}
#endif
frameCache->reset();
dataAlloc->reset();
traceAlloc->reset();

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

@ -290,11 +290,7 @@
#define JS_MIN(x,y) ((x)<(y)?(x):(y))
#define JS_MAX(x,y) ((x)>(y)?(x):(y))
#ifdef _MSC_VER
# include "jscpucfg.h" /* We can't auto-detect MSVC configuration */
#else
# include "jsautocfg.h" /* Use auto-detected configuration */
#endif
#include "jscpucfg.h"
/*
* Define JS_64BIT iff we are building in an environment with 64-bit

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

@ -84,6 +84,8 @@ WatchpointMap::watch(JSContext *cx, JSObject *obj, jsid id,
JSWatchPointHandler handler, JSObject *closure)
{
JS_ASSERT(id == js_CheckForStringIndex(id));
JS_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id));
obj->setWatched(cx);
Watchpoint w;
w.handler = handler;

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

@ -723,10 +723,9 @@ JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
if (xdr->mode == JSXDR_DECODE) {
JS_ASSERT(!script->compileAndGo);
if (!js_NewScriptObject(xdr->cx, script))
return false;
script->u.globalObject = GetCurrentGlobal(xdr->cx);
js_CallNewScriptHook(xdr->cx, script, NULL);
Debugger::onNewScript(xdr->cx, script, script->u.object, NULL);
Debugger::onNewScript(xdr->cx, script, NULL);
*scriptp = script;
}

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

@ -112,7 +112,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi
setGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())),
callICs(CompilerAllocPolicy(cx, *thisFromCtor())),
equalityICs(CompilerAllocPolicy(cx, *thisFromCtor())),
traceICs(CompilerAllocPolicy(cx, *thisFromCtor())),
#endif
#if defined JS_POLYIC
pics(CompilerAllocPolicy(cx, *thisFromCtor())),
@ -127,14 +126,8 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi
jumpTables(CompilerAllocPolicy(cx, *thisFromCtor())),
jumpTableOffsets(CompilerAllocPolicy(cx, *thisFromCtor())),
loopEntries(CompilerAllocPolicy(cx, *thisFromCtor())),
rootedObjects(CompilerAllocPolicy(cx, *thisFromCtor())),
stubcc(cx, *thisFromCtor(), frame),
debugMode_(cx->compartment->debugMode()),
#if defined JS_TRACER
addTraceHints(cx->traceJitEnabled),
#else
addTraceHints(false),
#endif
inlining_(false),
hasGlobalReallocation(false),
oomInVector(false),
@ -143,10 +136,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi
applyTricks(NoApplyTricks),
pcLengths(NULL)
{
/* :FIXME: bug 637856 disabling traceJit if inference is enabled */
if (cx->typeInferenceEnabled())
addTraceHints = false;
/* Once a script starts getting really hot we will inline calls in it. */
if (!debugMode() && cx->typeInferenceEnabled() && globalObj &&
(outerScript->getUseCount() >= USES_BEFORE_INLINING ||
@ -760,10 +749,9 @@ mjit::Compiler::generatePrologue()
/*
* Set locals to undefined, as in initCallFrameLatePrologue.
* Skip locals which aren't closed and are known to be defined before used,
* :FIXME: bug 604541: write undefined if we might be using the tracer, so it works.
*/
for (uint32 i = 0; i < script->nfixed; i++) {
if (analysis->localHasUseBeforeDef(i) || addTraceHints) {
if (analysis->localHasUseBeforeDef(i)) {
Address local(JSFrameReg, sizeof(StackFrame) + i * sizeof(Value));
masm.storeValue(UndefinedValue(), local);
}
@ -968,13 +956,11 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
sizeof(NativeMapEntry) * nNmapLive +
sizeof(InlineFrame) * inlineFrames.length() +
sizeof(CallSite) * callSites.length() +
sizeof(JSObject *) * rootedObjects.length() +
#if defined JS_MONOIC
sizeof(ic::GetGlobalNameIC) * getGlobalNames.length() +
sizeof(ic::SetGlobalNameIC) * setGlobalNames.length() +
sizeof(ic::CallICInfo) * callICs.length() +
sizeof(ic::EqualityICInfo) * equalityICs.length() +
sizeof(ic::TraceICInfo) * traceICs.length() +
#endif
#if defined JS_POLYIC
sizeof(ic::PICInfo) * pics.length() +
@ -1100,13 +1086,6 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
stubCode.patch(from.loopPatch.codePatch, result + codeOffset);
}
/* Build the list of objects rooted by the script. */
JSObject **jitRooted = (JSObject **)cursor;
jit->nRootedObjects = rootedObjects.length();
cursor += sizeof(JSObject *) * jit->nRootedObjects;
for (size_t i = 0; i < jit->nRootedObjects; i++)
jitRooted[i] = rootedObjects[i];
#if defined JS_MONOIC
JS_INIT_CLIST(&jit->callers);
@ -1249,43 +1228,6 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
stubCode.patch(equalityICs[i].addrLabel, &jitEqualityICs[i]);
}
ic::TraceICInfo *jitTraceICs = (ic::TraceICInfo *)cursor;
jit->nTraceICs = traceICs.length();
cursor += sizeof(ic::TraceICInfo) * jit->nTraceICs;
for (size_t i = 0; i < jit->nTraceICs; i++) {
jitTraceICs[i].initialized = traceICs[i].initialized;
if (!traceICs[i].initialized)
continue;
if (traceICs[i].fastTrampoline) {
jitTraceICs[i].fastTarget = stubCode.locationOf(traceICs[i].trampolineStart);
} else {
uint32 offs = uint32(traceICs[i].jumpTarget - script->code);
JS_ASSERT(jumpMap[offs].isSet());
jitTraceICs[i].fastTarget = fullCode.locationOf(jumpMap[offs]);
}
jitTraceICs[i].slowTarget = stubCode.locationOf(traceICs[i].trampolineStart);
jitTraceICs[i].traceHint = fullCode.locationOf(traceICs[i].traceHint);
jitTraceICs[i].stubEntry = stubCode.locationOf(traceICs[i].stubEntry);
jitTraceICs[i].traceData = NULL;
#ifdef DEBUG
jitTraceICs[i].jumpTargetPC = traceICs[i].jumpTarget;
#endif
jitTraceICs[i].hasSlowTraceHint = traceICs[i].slowTraceHint.isSet();
if (traceICs[i].slowTraceHint.isSet())
jitTraceICs[i].slowTraceHint = stubCode.locationOf(traceICs[i].slowTraceHint.get());
#ifdef JS_TRACER
uint32 hotloop = GetHotloop(cx);
uint32 prevCount = cx->compartment->backEdgeCount(traceICs[i].jumpTarget);
jitTraceICs[i].loopCounterStart = hotloop;
jitTraceICs[i].loopCounter = hotloop < prevCount ? 1 : hotloop - prevCount;
#endif
stubCode.patch(traceICs[i].addrLabel, &jitTraceICs[i]);
}
#endif /* JS_MONOIC */
for (size_t i = 0; i < callPatches.length(); i++) {
@ -4715,12 +4657,6 @@ mjit::Compiler::jsop_callprop_str(JSAtom *atom)
if (!obj)
return false;
/*
* Root the proto, since JS_ClearScope might overwrite the global object's
* copy.
*/
rootedObjects.append(obj);
/* Force into a register because getprop won't expect a constant. */
RegisterID reg = frame.allocReg();
@ -6838,150 +6774,50 @@ mjit::Compiler::jumpAndTrace(Jump j, jsbytecode *target, Jump *slow, bool *tramp
consistent = frame.consistentRegisters(target);
}
if (!addTraceHints || target >= PC ||
(JSOp(*target) != JSOP_TRACE && JSOp(*target) != JSOP_NOTRACE)
#ifdef JS_MONOIC
|| GET_UINT16(target) == BAD_TRACEIC_INDEX
#endif
)
{
if (!lvtarget || lvtarget->synced()) {
JS_ASSERT(consistent);
if (!jumpInScript(j, target))
return false;
if (slow && !stubcc.jumpInScript(*slow, target))
return false;
} else {
if (consistent) {
if (!jumpInScript(j, target))
return false;
} else {
/*
* Make a trampoline to issue remaining loads for the register
* state at target.
*/
Label start = stubcc.masm.label();
stubcc.linkExitDirect(j, start);
frame.prepareForJump(target, stubcc.masm, false);
if (!stubcc.jumpInScript(stubcc.masm.jump(), target))
return false;
if (trampoline)
*trampoline = true;
if (pcLengths) {
/*
* This is OOL code but will usually be executed, so track
* it in the CODE_LENGTH for the opcode.
*/
uint32 offset = ssa.frameLength(a->inlineIndex) + PC - script->code;
size_t length = stubcc.masm.size() - stubcc.masm.distanceOf(start);
pcLengths[offset].codeLength += length;
}
}
if (slow) {
slow->linkTo(stubcc.masm.label(), &stubcc.masm);
frame.prepareForJump(target, stubcc.masm, true);
if (!stubcc.jumpInScript(stubcc.masm.jump(), target))
return false;
}
}
if (target < PC)
return finishLoop(target);
return true;
}
/* The trampoline should not be specified if we need to generate a trace IC. */
JS_ASSERT(!trampoline);
#ifndef JS_TRACER
JS_NOT_REACHED("Bad addTraceHints");
return false;
#else
# if JS_MONOIC
TraceGenInfo ic;
ic.initialized = true;
ic.stubEntry = stubcc.masm.label();
ic.traceHint = j;
if (slow)
ic.slowTraceHint = *slow;
uint16 index = GET_UINT16(target);
if (traceICs.length() <= index)
if (!traceICs.resize(index+1))
if (!lvtarget || lvtarget->synced()) {
JS_ASSERT(consistent);
if (!jumpInScript(j, target))
return false;
# endif
Label traceStart = stubcc.masm.label();
stubcc.linkExitDirect(j, traceStart);
if (slow)
slow->linkTo(traceStart, &stubcc.masm);
# if JS_MONOIC
ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
Jump nonzero = stubcc.masm.branchSub32(Assembler::NonZero, Imm32(1),
Address(Registers::ArgReg1,
offsetof(TraceICInfo, loopCounter)));
# endif
/* Save and restore compiler-tracked PC, so cx->regs is right in InvokeTracer. */
{
jsbytecode* pc = PC;
PC = target;
OOL_STUBCALL(stubs::InvokeTracer, REJOIN_NONE);
PC = pc;
}
Jump no = stubcc.masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
Registers::ReturnReg);
if (!cx->typeInferenceEnabled())
stubcc.masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
stubcc.masm.jump(Registers::ReturnReg);
no.linkTo(stubcc.masm.label(), &stubcc.masm);
#ifdef JS_MONOIC
nonzero.linkTo(stubcc.masm.label(), &stubcc.masm);
ic.jumpTarget = target;
ic.fastTrampoline = !consistent;
ic.trampolineStart = stubcc.masm.label();
traceICs[index] = ic;
#endif
/*
* Jump past the tracer call if the trace has been blacklisted. We still make
* a trace IC in such cases, in case it is un-blacklisted later.
*/
if (JSOp(*target) == JSOP_NOTRACE) {
if (slow && !stubcc.jumpInScript(*slow, target))
return false;
} else {
if (consistent) {
if (!jumpInScript(j, target))
return false;
} else {
stubcc.linkExitDirect(j, stubcc.masm.label());
/*
* Make a trampoline to issue remaining loads for the register
* state at target.
*/
Label start = stubcc.masm.label();
stubcc.linkExitDirect(j, start);
frame.prepareForJump(target, stubcc.masm, false);
if (!stubcc.jumpInScript(stubcc.masm.jump(), target))
return false;
if (trampoline)
*trampoline = true;
if (pcLengths) {
/*
* This is OOL code but will usually be executed, so track
* it in the CODE_LENGTH for the opcode.
*/
uint32 offset = ssa.frameLength(a->inlineIndex) + PC - script->code;
size_t length = stubcc.masm.size() - stubcc.masm.distanceOf(start);
pcLengths[offset].codeLength += length;
}
}
if (slow)
if (slow) {
slow->linkTo(stubcc.masm.label(), &stubcc.masm);
frame.prepareForJump(target, stubcc.masm, true);
if (!stubcc.jumpInScript(stubcc.masm.jump(), target))
return false;
}
}
/*
* Reload any registers needed at the head of the loop. Note that we didn't
* need to do syncing before calling InvokeTracer, as state is always synced
* on backwards jumps.
*/
frame.prepareForJump(target, stubcc.masm, true);
if (!stubcc.jumpInScript(stubcc.masm.jump(), target))
return false;
#endif
return finishLoop(target);
if (target < PC)
return finishLoop(target);
return true;
}
void

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

@ -125,19 +125,6 @@ class Compiler : public BaseCompiler
Assembler::Condition cond;
JSC::MacroAssembler::RegisterID tempReg;
};
struct TraceGenInfo {
bool initialized;
Label stubEntry;
DataLabelPtr addrLabel;
jsbytecode *jumpTarget;
bool fastTrampoline;
Label trampolineStart;
Jump traceHint;
MaybeJump slowTraceHint;
TraceGenInfo() : initialized(false) {}
};
/* InlineFrameAssembler wants to see this. */
public:
@ -449,7 +436,6 @@ private:
js::Vector<SetGlobalNameICInfo, 16, CompilerAllocPolicy> setGlobalNames;
js::Vector<CallGenInfo, 64, CompilerAllocPolicy> callICs;
js::Vector<EqualityGenInfo, 64, CompilerAllocPolicy> equalityICs;
js::Vector<TraceGenInfo, 64, CompilerAllocPolicy> traceICs;
#endif
#if defined JS_POLYIC
js::Vector<PICGenInfo, 16, CompilerAllocPolicy> pics;
@ -464,7 +450,6 @@ private:
js::Vector<JumpTable, 16> jumpTables;
js::Vector<uint32, 16> jumpTableOffsets;
js::Vector<LoopEntry, 16> loopEntries;
js::Vector<JSObject *, 0, CompilerAllocPolicy> rootedObjects;
StubCompiler stubcc;
Label invokeLabel;
Label arityLabel;
@ -475,7 +460,6 @@ private:
Jump argsCheckJump;
#endif
bool debugMode_;
bool addTraceHints;
bool inlining_;
bool hasGlobalReallocation;
bool oomInVector; // True if we have OOM'd appending to a vector.

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

@ -1162,7 +1162,7 @@ mjit::Compiler::jsop_equality_int_string(JSOp op, BoolStub stub,
ic.stubEntry = stubEntry;
ic.stub = stub;
bool useIC = (!addTraceHints || target >= PC) && !a->parent;
bool useIC = !a->parent;
/* Call the IC stub, which may generate a fast path. */
if (useIC) {

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

@ -187,26 +187,6 @@ mjit::Compiler::jsop_bitop(JSOp op)
return;
}
bool lhsIntOrDouble = !(lhs->isNotType(JSVAL_TYPE_DOUBLE) &&
lhs->isNotType(JSVAL_TYPE_INT32));
/* Fast-path double to int conversion. */
if (!lhs->isConstant() && rhs->isConstant() && lhsIntOrDouble &&
rhs->isType(JSVAL_TYPE_INT32) && rhs->getValue().toInt32() == 0 &&
(op == JSOP_BITOR || op == JSOP_LSH)) {
ensureInteger(lhs, Uses(2));
RegisterID reg = frame.ownRegForData(lhs);
stubcc.leave();
OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
frame.popn(2);
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
stubcc.rejoin(Changes(1));
return;
}
/* Convert a double RHS to integer if it's constant for the test below. */
if (rhs->isConstant() && rhs->getValue().isDouble())
rhs->convertConstantDoubleToInt32(cx);
@ -282,7 +262,7 @@ mjit::Compiler::jsop_bitop(JSOp op)
masm.and32(Imm32(rhsInt), reg);
else if (op == JSOP_BITXOR)
masm.xor32(Imm32(rhsInt), reg);
else
else if (rhsInt != 0)
masm.or32(Imm32(rhsInt), reg);
} else if (frame.shouldAvoidDataRemat(rhs)) {
Address rhsAddr = masm.payloadOf(frame.addressOf(rhs));

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

@ -1325,11 +1325,7 @@ FrameState::sync(Assembler &masm, Uses uses) const
Registers avail(freeRegs.freeMask & Registers::AvailRegs);
Registers temp(Registers::TempAnyRegs);
FrameEntry *bottom = (cx->typeInferenceEnabled() || cx->compartment->debugMode())
? entries
: a->sp - uses.nuses;
for (FrameEntry *fe = a->sp - 1; fe >= bottom; fe--) {
for (FrameEntry *fe = a->sp - 1; fe >= entries; fe--) {
if (!fe->isTracked())
continue;
@ -1379,7 +1375,7 @@ FrameState::sync(Assembler &masm, Uses uses) const
/* Fall back to a slower sync algorithm if load required. */
if ((!fe->type.synced() && backing->type.inMemory()) ||
(!fe->data.synced() && backing->data.inMemory())) {
syncFancy(masm, avail, fe, bottom);
syncFancy(masm, avail, fe, entries);
return;
}
#endif
@ -1460,11 +1456,7 @@ FrameState::syncAndKill(Registers kill, Uses uses, Uses ignore)
uint32 maxvisits = tracker.nentries;
FrameEntry *bottom = (cx->typeInferenceEnabled() || cx->compartment->debugMode())
? entries
: a->sp - uses.nuses;
for (FrameEntry *fe = a->sp - 1; fe >= bottom && maxvisits; fe--) {
for (FrameEntry *fe = a->sp - 1; fe >= entries && maxvisits; fe--) {
if (!fe->isTracked())
continue;

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

@ -533,21 +533,7 @@ js_InternalThrow(VMFrame &f)
// or SplatApplyArgs threw an exception.
RemoveOrphanedNative(cx, f.fp());
// It's possible that from within RunTracer(), Interpret() returned with
// an error and finished the frame (i.e., called ScriptEpilogue), but has
// not yet performed an inline return.
//
// In this case, RunTracer() has no choice but to propagate the error
// up to the method JIT, and thus to this function. But ScriptEpilogue()
// has already been called. Detect this, and avoid double-finishing the
// frame. See HandleErrorInExcessFrame() and bug 624100.
if (f.fp()->finishedInInterpreter()) {
// If it's the last frame, just propagate the failure up again.
if (f.fp() == f.entryfp)
return NULL;
InlineReturn(f);
}
JS_ASSERT(!f.fp()->finishedInInterpreter());
// Make sure sp is up to date.
JS_ASSERT(&cx->regs() == &f.regs);
@ -616,50 +602,46 @@ js_InternalThrow(VMFrame &f)
StackFrame *fp = cx->fp();
JSScript *script = fp->script();
if (cx->typeInferenceEnabled() || !fp->jit()) {
/*
* Fall back to EnterMethodJIT and finish the frame in the interpreter.
* With type inference enabled, we may wipe out all JIT code on the
* stack without patching ncode values to jump to the interpreter, and
* thus can only enter JIT code via EnterMethodJIT (which overwrites
* its entry frame's ncode). See ClearAllFrames.
*/
cx->compartment->jaegerCompartment()->setLastUnfinished(Jaeger_Unfinished);
if (!script->ensureRanAnalysis(cx)) {
js_ReportOutOfMemory(cx);
return NULL;
}
analyze::AutoEnterAnalysis enter(cx);
cx->regs().pc = pc;
cx->regs().sp = fp->base() + script->analysis()->getCode(pc).stackDepth;
/*
* Interpret the ENTERBLOCK and EXCEPTION opcodes, so that we don't go
* back into the interpreter with a pending exception. This will cause
* it to immediately rethrow.
*/
if (cx->isExceptionPending()) {
JS_ASSERT(js_GetOpcode(cx, script, pc) == JSOP_ENTERBLOCK);
JSObject *obj = script->getObject(GET_SLOTNO(pc));
Value *vp = cx->regs().sp + OBJ_BLOCK_COUNT(cx, obj);
SetValueRangeToUndefined(cx->regs().sp, vp);
cx->regs().sp = vp;
JS_ASSERT(js_GetOpcode(cx, script, pc + JSOP_ENTERBLOCK_LENGTH) == JSOP_EXCEPTION);
cx->regs().sp[0] = cx->getPendingException();
cx->clearPendingException();
cx->regs().sp++;
cx->regs().pc = pc + JSOP_ENTERBLOCK_LENGTH + JSOP_EXCEPTION_LENGTH;
}
*f.oldregs = f.regs;
/*
* Fall back to EnterMethodJIT and finish the frame in the interpreter.
* With type inference enabled, we may wipe out all JIT code on the
* stack without patching ncode values to jump to the interpreter, and
* thus can only enter JIT code via EnterMethodJIT (which overwrites
* its entry frame's ncode). See ClearAllFrames.
*/
cx->compartment->jaegerCompartment()->setLastUnfinished(Jaeger_Unfinished);
if (!script->ensureRanAnalysis(cx)) {
js_ReportOutOfMemory(cx);
return NULL;
}
return script->nativeCodeForPC(fp->isConstructing(), pc);
analyze::AutoEnterAnalysis enter(cx);
cx->regs().pc = pc;
cx->regs().sp = fp->base() + script->analysis()->getCode(pc).stackDepth;
/*
* Interpret the ENTERBLOCK and EXCEPTION opcodes, so that we don't go
* back into the interpreter with a pending exception. This will cause
* it to immediately rethrow.
*/
if (cx->isExceptionPending()) {
JS_ASSERT(js_GetOpcode(cx, script, pc) == JSOP_ENTERBLOCK);
JSObject *obj = script->getObject(GET_SLOTNO(pc));
Value *vp = cx->regs().sp + OBJ_BLOCK_COUNT(cx, obj);
SetValueRangeToUndefined(cx->regs().sp, vp);
cx->regs().sp = vp;
JS_ASSERT(js_GetOpcode(cx, script, pc + JSOP_ENTERBLOCK_LENGTH) == JSOP_EXCEPTION);
cx->regs().sp[0] = cx->getPendingException();
cx->clearPendingException();
cx->regs().sp++;
cx->regs().pc = pc + JSOP_ENTERBLOCK_LENGTH + JSOP_EXCEPTION_LENGTH;
}
*f.oldregs = f.regs;
return NULL;
}
void JS_FASTCALL
@ -701,481 +683,8 @@ stubs::ScriptProbeOnlyEpilogue(VMFrame &f)
Probes::exitJSFun(f.cx, f.fp()->fun(), f.fp()->script());
}
#ifdef JS_TRACER
/*
* Called when an error is in progress and the topmost frame could not handle
* it. This will unwind to a given frame, or find and align to an exception
* handler in the process.
*/
static inline bool
HandleErrorInExcessFrame(VMFrame &f, StackFrame *stopFp, bool searchedTopmostFrame = true)
{
JSContext *cx = f.cx;
/*
* Callers of this called either Interpret() or JaegerShot(), which would
* have searched for exception handlers already. If we see stopFp, just
* return false. Otherwise, pop the frame, since it's guaranteed useless.
*
* Note that this also guarantees ScriptEpilogue() has been called.
*/
StackFrame *fp = cx->fp();
if (searchedTopmostFrame) {
/*
* This is a special case meaning that fp->finishedInInterpreter() is
* true. If so, and fp == stopFp, our only choice is to propagate this
* error up, back to the method JIT, and then to js_InternalThrow,
* where this becomes a special case. See the comment there and bug
* 624100.
*/
if (fp == stopFp)
return false;
/*
* Otherwise, the protocol here (like Invoke) is to assume that the
* execution mode finished the frame, and to just pop it.
*/
InlineReturn(f);
}
/* Remove the bottom frame. */
bool returnOK = false;
for (;;) {
fp = cx->fp();
/* Clear imacros. */
if (fp->hasImacropc()) {
cx->regs().pc = fp->imacropc();
fp->clearImacropc();
}
JS_ASSERT(!fp->hasImacropc());
/* If there's an exception and a handler, set the pc and leave. */
if (cx->isExceptionPending()) {
jsbytecode *pc = FindExceptionHandler(cx);
if (pc) {
cx->regs().pc = pc;
returnOK = true;
break;
}
}
/* Don't unwind if this was the entry frame. */
if (fp == stopFp)
break;
/* Unwind and return. */
returnOK &= UnwindScope(cx, 0, returnOK || cx->isExceptionPending());
returnOK = ScriptEpilogue(cx, fp, returnOK);
InlineReturn(f);
}
JS_ASSERT(&f.regs == &cx->regs());
JS_ASSERT_IF(!returnOK, cx->fp() == stopFp);
return returnOK;
}
/* Returns whether the current PC has method JIT'd code. */
static inline void *
AtSafePoint(JSContext *cx)
{
StackFrame *fp = cx->fp();
if (fp->hasImacropc())
return NULL;
JSScript *script = fp->script();
return script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs().pc);
}
/*
* Interprets until either a safe point is reached that has method JIT'd
* code, or the current frame tries to return.
*/
static inline JSBool
PartialInterpret(VMFrame &f)
{
JSContext *cx = f.cx;
StackFrame *fp = cx->fp();
#ifdef DEBUG
JSScript *script = fp->script();
JS_ASSERT(!fp->finishedInInterpreter());
JS_ASSERT(fp->hasImacropc() ||
!script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs().pc));
#endif
JSBool ok = JS_TRUE;
ok = Interpret(cx, fp, JSINTERP_SAFEPOINT);
return ok;
}
JS_STATIC_ASSERT(JSOP_NOP == 0);
/*
* Returns whether the current PC would return, or if the frame has already
* been completed. This distinction avoids re-entering the interpreter or JIT
* to complete a JSOP_RETURN. Instead, that edge case is handled in
* HandleFinishedFrame. We could consider reducing complexity, and making this
* function return only "finishedInInterpreter", and always using the full VM
* machinery to fully finish frames.
*/
static inline bool
FrameIsFinished(JSContext *cx)
{
JSOp op = JSOp(*cx->regs().pc);
return (op == JSOP_RETURN ||
op == JSOP_RETRVAL ||
op == JSOP_STOP)
? true
: cx->fp()->finishedInInterpreter();
}
/*
* Given a frame that is about to return, make sure its return value and
* activation objects are fixed up. Then, pop the frame and advance the
* current PC. Note that while we could enter the JIT at this point, the
* logic would still be necessary for the interpreter, so it's easier
* (and faster) to finish frames in C++ even if at a safe point here.
*/
static bool
HandleFinishedFrame(VMFrame &f, StackFrame *entryFrame)
{
JSContext *cx = f.cx;
JS_ASSERT(FrameIsFinished(cx));
/*
* This is the most difficult and complicated piece of the tracer
* integration, and historically has been very buggy. The problem is that
* although this frame has to be popped (see RemoveExcessFrames), it may
* be at a JSOP_RETURN opcode, and it might not have ever been executed.
* That is, fp->rval may not be set to the top of the stack, and if it
* has, the stack has already been decremented. Note that fp->rval is not
* the only problem: the epilogue may never have been executed.
*
* Here are the edge cases and whether the frame has been exited cleanly:
* 1. No: A trace exited directly before a RETURN op, and the
* interpreter never ran.
* 2. Yes: The interpreter exited cleanly.
* 3. No: The interpreter exited on a safe point. LEAVE_ON_SAFE_POINT
* is not used in between JSOP_RETURN and advancing the PC,
* therefore, it cannot have been run if at a safe point.
* 4. No: Somewhere in the RunTracer call tree, we removed a frame,
* and we returned to a JSOP_RETURN opcode. Note carefully
* that in this situation, FrameIsFinished() returns true!
* 5. Yes: The function exited in the method JIT, during
* FinishExcessFrames() However, in this case, we'll never enter
* HandleFinishedFrame(): we always immediately pop JIT'd frames.
*
* Since the only scenario where this fixup is NOT needed is a normal exit
* from the interpreter, we can cleanly check for this scenario by checking
* a bit it sets in the frame.
*/
bool returnOK = true;
if (!cx->fp()->finishedInInterpreter()) {
if (JSOp(*cx->regs().pc) == JSOP_RETURN)
cx->fp()->setReturnValue(f.regs.sp[-1]);
returnOK = ScriptEpilogue(cx, cx->fp(), true);
}
if (cx->fp() != entryFrame) {
InlineReturn(f);
}
return returnOK;
}
/*
* Given a frame newer than the entry frame, try to finish it. If it's at a
* return position, pop the frame. If it's at a safe point, execute it in
* Jaeger code. Otherwise, try to interpret until a safe point.
*
* While this function is guaranteed to make progress, it may not actually
* finish or pop the current frame. It can either:
* 1) Finalize a finished frame, or
* 2) Finish and finalize the frame in the Method JIT, or
* 3) Interpret, which can:
* a) Propagate an error, or
* b) Finish the frame, but not finalize it, or
* c) Abruptly leave at any point in the frame, or in a newer frame
* pushed by a call, that has method JIT'd code.
*/
static bool
EvaluateExcessFrame(VMFrame &f, StackFrame *entryFrame)
{
JSContext *cx = f.cx;
StackFrame *fp = cx->fp();
/*
* A "finished" frame is when the interpreter rested on a STOP,
* RETURN, RETRVAL, etc. We check for finished frames BEFORE looking
* for a safe point. If the frame was finished, we could have already
* called ScriptEpilogue(), and entering the JIT could call it twice.
*/
if (!fp->hasImacropc() && FrameIsFinished(cx))
return HandleFinishedFrame(f, entryFrame);
if (void *ncode = AtSafePoint(cx)) {
if (!JaegerShotAtSafePoint(cx, ncode, false))
return false;
InlineReturn(f);
return true;
}
return PartialInterpret(f);
}
/*
* Evaluate frames newer than the entry frame until all are gone. This will
* always leave f.regs.fp == entryFrame.
*/
static bool
FinishExcessFrames(VMFrame &f, StackFrame *entryFrame)
{
JSContext *cx = f.cx;
while (cx->fp() != entryFrame || entryFrame->hasImacropc()) {
if (!EvaluateExcessFrame(f, entryFrame)) {
if (!HandleErrorInExcessFrame(f, entryFrame))
return false;
}
}
return true;
}
#if defined JS_MONOIC
static void
UpdateTraceHintSingle(Repatcher &repatcher, JSC::CodeLocationJump jump, JSC::CodeLocationLabel target)
{
/*
* Hack: The value that will be patched is before the executable address,
* so to get protection right, just unprotect the general region around
* the jump.
*/
repatcher.relink(jump, target);
JaegerSpew(JSpew_PICs, "relinking trace hint %p to %p\n",
jump.executableAddress(), target.executableAddress());
}
static void
DisableTraceHint(JITScript *jit, ic::TraceICInfo &ic)
{
Repatcher repatcher(jit);
UpdateTraceHintSingle(repatcher, ic.traceHint, ic.fastTarget);
if (ic.hasSlowTraceHint)
UpdateTraceHintSingle(repatcher, ic.slowTraceHint, ic.slowTarget);
}
static void
ResetTraceHintAt(JSScript *script, js::mjit::JITScript *jit,
jsbytecode *pc, uint16_t index, bool full)
{
if (index >= jit->nTraceICs)
return;
ic::TraceICInfo &ic = jit->traceICs()[index];
if (!ic.initialized)
return;
JS_ASSERT(ic.jumpTargetPC == pc);
JaegerSpew(JSpew_PICs, "Enabling trace IC %u in script %p\n", index,
static_cast<void*>(script));
Repatcher repatcher(jit);
UpdateTraceHintSingle(repatcher, ic.traceHint, ic.stubEntry);
if (ic.hasSlowTraceHint)
UpdateTraceHintSingle(repatcher, ic.slowTraceHint, ic.stubEntry);
if (full) {
ic.traceData = NULL;
ic.loopCounterStart = 1;
ic.loopCounter = ic.loopCounterStart;
}
}
#endif
void
js::mjit::ResetTraceHint(JSScript *script, jsbytecode *pc, uint16_t index, bool full)
{
#if JS_MONOIC
if (script->jitNormal)
ResetTraceHintAt(script, script->jitNormal, pc, index, full);
if (script->jitCtor)
ResetTraceHintAt(script, script->jitCtor, pc, index, full);
#endif
}
#if JS_MONOIC
void *
RunTracer(VMFrame &f, ic::TraceICInfo &ic)
#else
void *
RunTracer(VMFrame &f)
#endif
{
JSContext *cx = f.cx;
StackFrame *entryFrame = f.fp();
TracePointAction tpa;
/* :TODO: nuke PIC? */
if (!cx->traceJitEnabled)
return NULL;
/*
* Force initialization of the entry frame's scope chain and return value,
* if necessary. The tracer can query the scope chain without needing to
* check the HAS_SCOPECHAIN flag, and the frame is guaranteed to have the
* correct return value stored if we trace/interpret through to the end
* of the frame.
*/
entryFrame->scopeChain();
entryFrame->returnValue();
bool blacklist;
void **traceData;
uintN *traceEpoch;
uint32 *loopCounter;
uint32 hits;
#if JS_MONOIC
traceData = &ic.traceData;
traceEpoch = &ic.traceEpoch;
loopCounter = &ic.loopCounter;
*loopCounter = 1;
hits = ic.loopCounterStart;
#else
traceData = NULL;
traceEpoch = NULL;
loopCounter = NULL;
hits = 1;
#endif
{
/*
* While the tracer is running, redirect the regs to a local variable here.
* If the tracer exits during an inlined frame, it will synthesize those
* frames, point f.regs.fp at them and then enter the interpreter. If the
* interpreter pops the frames it will not be reflected here as a local
* set of regs is used by the interpreter, and f->regs end up pointing at
* garbage, confusing the recompiler.
*/
FrameRegs regs = f.regs;
PreserveRegsGuard regsGuard(cx, regs);
tpa = MonitorTracePoint(f.cx, &blacklist, traceData, traceEpoch,
loopCounter, hits);
JS_ASSERT(!TRACE_RECORDER(cx));
}
#if JS_MONOIC
ic.loopCounterStart = *loopCounter;
if (blacklist)
DisableTraceHint(entryFrame->jit(), ic);
#endif
// Even though ExecuteTree() bypasses the interpreter, it should propagate
// error failures correctly.
JS_ASSERT_IF(cx->isExceptionPending(), tpa == TPA_Error);
JS_ASSERT(f.fp() == cx->fp());
switch (tpa) {
case TPA_Nothing:
return NULL;
case TPA_Error:
if (!HandleErrorInExcessFrame(f, entryFrame, f.fp()->finishedInInterpreter()))
THROWV(NULL);
JS_ASSERT(!cx->fp()->hasImacropc());
break;
case TPA_RanStuff:
case TPA_Recorded:
break;
}
/*
* The tracer could have dropped us off on any frame at any position.
* Well, it could not have removed frames (recursion is disabled).
*
* Frames after the entryFrame cannot be entered via JaegerShotAtSafePoint()
* unless each is at a safe point. We can JaegerShotAtSafePoint these
* frames individually, but we must unwind to the entryFrame.
*
* Note carefully that JaegerShotAtSafePoint can resume methods at
* arbitrary safe points whereas JaegerShot cannot.
*
* If we land on entryFrame without a safe point in sight, we'll end up
* at the RETURN op. This is an edge case with two paths:
*
* 1) The entryFrame is the last inline frame. If it fell on a RETURN,
* move the return value down.
* 2) The entryFrame is NOT the last inline frame. Pop the frame.
*
* In both cases, we hijack the stub to return to the force-return
* trampoline. This trampoline simulates the frame-popping portion of
* emitReturn (except without the benefit of the FrameState) and will
* produce the necessary register state to return to the caller.
*/
restart:
/* Step 1. Finish frames created after the entry frame. */
if (!FinishExcessFrames(f, entryFrame))
THROWV(NULL);
/* IMacros are guaranteed to have been removed by now. */
JS_ASSERT(f.fp() == entryFrame);
JS_ASSERT(!entryFrame->hasImacropc());
/* Step 2. If entryFrame is done, use a special path to return to EnterMethodJIT(). */
if (FrameIsFinished(cx)) {
if (!HandleFinishedFrame(f, entryFrame))
THROWV(NULL);
*f.returnAddressLocation() = cx->jaegerCompartment()->forceReturnFromFastCall();
return NULL;
}
/* Step 3. If entryFrame is at a safe point, just leave. */
if (void *ncode = AtSafePoint(cx))
return ncode;
/* Step 4. Do a partial interp, then restart the whole process. */
if (!PartialInterpret(f)) {
if (!HandleErrorInExcessFrame(f, entryFrame))
THROWV(NULL);
}
goto restart;
}
#endif /* JS_TRACER */
#if defined JS_TRACER
# if defined JS_MONOIC
void *JS_FASTCALL
stubs::InvokeTracer(VMFrame &f, ic::TraceICInfo *ic)
{
return RunTracer(f, *ic);
}
# else
void *JS_FASTCALL
stubs::InvokeTracer(VMFrame &f)
{
return RunTracer(f);
}
# endif /* JS_MONOIC */
#endif /* JS_TRACER */
/* :XXX: common out with identical copy in Compiler.cpp */
#if defined(JS_METHODJIT_SPEW)
static const char *OpcodeNames[] = {

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

@ -1091,16 +1091,10 @@ JITScript::callSites() const
return (js::mjit::CallSite *)&inlineFrames()[nInlineFrames];
}
JSObject **
JITScript::rootedObjects() const
{
return (JSObject **)&callSites()[nCallSites];
}
char *
JITScript::commonSectionLimit() const
{
return (char *)&rootedObjects()[nRootedObjects];
return (char *)&callSites()[nCallSites];
}
#ifdef JS_MONOIC
@ -1129,16 +1123,10 @@ JITScript::equalityICs() const
return (ic::EqualityICInfo *)&callICs()[nCallICs];
}
ic::TraceICInfo *
JITScript::traceICs() const
{
return (ic::TraceICInfo *)&equalityICs()[nEqualityICs];
}
char *
JITScript::monoICSectionsLimit() const
{
return (char *)&traceICs()[nTraceICs];
return (char *)&equalityICs()[nEqualityICs];
}
#else // JS_MONOIC
char *
@ -1186,17 +1174,6 @@ static inline void Destroy(T &t)
t.~T();
}
void
mjit::JITScript::purgeNativeCallStubs()
{
for (unsigned i = 0; i < nativeCallStubs.length(); i++) {
JSC::ExecutablePool *pool = nativeCallStubs[i].pool;
if (pool)
pool->release();
}
nativeCallStubs.clear();
}
mjit::JITScript::~JITScript()
{
code.release();
@ -1227,7 +1204,11 @@ mjit::JITScript::~JITScript()
(*pExecPool)->release();
}
purgeNativeCallStubs();
for (unsigned i = 0; i < nativeCallStubs.length(); i++) {
JSC::ExecutablePool *pool = nativeCallStubs[i].pool;
if (pool)
pool->release();
}
ic::CallICInfo *callICs_ = callICs();
for (uint32 i = 0; i < nCallICs; i++) {
@ -1272,13 +1253,11 @@ mjit::JITScript::scriptDataSize(JSUsableSizeFun usf)
sizeof(NativeMapEntry) * nNmapPairs +
sizeof(InlineFrame) * nInlineFrames +
sizeof(CallSite) * nCallSites +
sizeof(JSObject *) * nRootedObjects +
#if defined JS_MONOIC
sizeof(ic::GetGlobalNameIC) * nGetGlobalNames +
sizeof(ic::SetGlobalNameIC) * nSetGlobalNames +
sizeof(ic::CallICInfo) * nCallICs +
sizeof(ic::EqualityICInfo) * nEqualityICs +
sizeof(ic::TraceICInfo) * nTraceICs +
#endif
#if defined JS_POLYIC
sizeof(ic::PICInfo) * nPICs +
@ -1413,20 +1392,4 @@ mjit::NativeToPC(JITScript *jit, void *ncode, mjit::CallSite **pinline)
return jit->nativeToPC(ncode, pinline);
}
void
JITScript::trace(JSTracer *trc)
{
/*
* MICs and PICs attached to the JITScript are weak references, and either
* entirely purged or selectively purged on each GC. We do, however, need
* to maintain references to any scripts whose code was inlined into this.
*/
InlineFrame *inlineFrames_ = inlineFrames();
for (unsigned i = 0; i < nInlineFrames; i++)
MarkObject(trc, *inlineFrames_[i].fun, "jitscript_fun");
for (uint32 i = 0; i < nRootedObjects; ++i)
MarkObject(trc, *rootedObjects()[i], "mjit rooted object");
}
/* static */ const double mjit::Assembler::oneDouble = 1.0;

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

@ -500,7 +500,6 @@ namespace ic {
struct GetGlobalNameIC;
struct SetGlobalNameIC;
struct EqualityICInfo;
struct TraceICInfo;
struct CallICInfo;
# endif
}
@ -531,7 +530,6 @@ typedef void * (JS_FASTCALL *VoidPtrStubCallIC)(VMFrame &, js::mjit::ic::CallICI
typedef void (JS_FASTCALL *VoidStubGetGlobal)(VMFrame &, js::mjit::ic::GetGlobalNameIC *);
typedef void (JS_FASTCALL *VoidStubSetGlobal)(VMFrame &, js::mjit::ic::SetGlobalNameIC *);
typedef JSBool (JS_FASTCALL *BoolStubEqualityIC)(VMFrame &, js::mjit::ic::EqualityICInfo *);
typedef void * (JS_FASTCALL *VoidPtrStubTraceIC)(VMFrame &, js::mjit::ic::TraceICInfo *);
#endif
#ifdef JS_POLYIC
typedef void (JS_FASTCALL *VoidStubPIC)(VMFrame &, js::mjit::ic::PICInfo *);
@ -605,13 +603,11 @@ struct JITScript {
bool singleStepMode:1; /* compiled in "single step mode" */
uint32 nInlineFrames;
uint32 nCallSites;
uint32 nRootedObjects;
#ifdef JS_MONOIC
uint32 nGetGlobalNames;
uint32 nSetGlobalNames;
uint32 nCallICs;
uint32 nEqualityICs;
uint32 nTraceICs;
#endif
#ifdef JS_POLYIC
uint32 nGetElems;
@ -643,13 +639,11 @@ struct JITScript {
NativeMapEntry *nmap() const;
js::mjit::InlineFrame *inlineFrames() const;
js::mjit::CallSite *callSites() const;
JSObject **rootedObjects() const;
#ifdef JS_MONOIC
ic::GetGlobalNameIC *getGlobalNames() const;
ic::SetGlobalNameIC *setGlobalNames() const;
ic::CallICInfo *callICs() const;
ic::EqualityICInfo *equalityICs() const;
ic::TraceICInfo *traceICs() const;
#endif
#ifdef JS_POLYIC
ic::GetElementIC *getElems() const;
@ -666,12 +660,6 @@ struct JITScript {
}
void nukeScriptDependentICs();
void sweepCallICs(JSContext *cx, bool purgeAll);
void purgeMICs();
void purgePICs();
void purgeNativeCallStubs();
void trace(JSTracer *trc);
/* |usf| can be NULL here, in which case the fallback size computation will be used. */
size_t scriptDataSize(JSUsableSizeFun usf);
@ -766,13 +754,6 @@ struct CallSite
}
};
/*
* Re-enables a tracepoint in the method JIT. When full is true, we
* also reset the iteration counter.
*/
void
ResetTraceHint(JSScript *script, jsbytecode *pc, uint16_t index, bool full);
uintN
GetCallTargetCount(JSScript *script, jsbytecode *pc);

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

@ -1386,168 +1386,5 @@ JITScript::resetArgsCheck()
repatch.relink(argsCheckJump, argsCheckStub);
}
void
JITScript::purgeMICs()
{
if (!nGetGlobalNames || !nSetGlobalNames)
return;
Repatcher repatch(this);
ic::GetGlobalNameIC *getGlobalNames_ = getGlobalNames();
for (uint32 i = 0; i < nGetGlobalNames; i++) {
ic::GetGlobalNameIC &ic = getGlobalNames_[i];
JSC::CodeLocationDataLabel32 label = ic.fastPathStart.dataLabel32AtOffset(ic.shapeOffset);
repatch.repatch(label, int(INVALID_SHAPE));
}
ic::SetGlobalNameIC *setGlobalNames_ = setGlobalNames();
for (uint32 i = 0; i < nSetGlobalNames; i++) {
ic::SetGlobalNameIC &ic = setGlobalNames_[i];
ic.patchInlineShapeGuard(repatch, int32(INVALID_SHAPE));
if (ic.hasExtraStub) {
Repatcher repatcher(ic.extraStub);
ic.patchExtraShapeGuard(repatcher, int32(INVALID_SHAPE));
}
}
}
void
ic::PurgeMICs(JSContext *cx, JSScript *script)
{
/* MICs are purged during GC to handle changing shapes. */
JS_ASSERT(cx->runtime->gcRegenShapes);
if (script->jitNormal)
script->jitNormal->purgeMICs();
if (script->jitCtor)
script->jitCtor->purgeMICs();
}
void
JITScript::nukeScriptDependentICs()
{
if (!nCallICs)
return;
Repatcher repatcher(this);
ic::CallICInfo *callICs_ = callICs();
for (uint32 i = 0; i < nCallICs; i++) {
ic::CallICInfo &ic = callICs_[i];
if (!ic.fastGuardedObject)
continue;
repatcher.repatch(ic.funGuard, NULL);
repatcher.relink(ic.funJump, ic.slowPathStart);
ic.releasePool(CallICInfo::Pool_ClosureStub);
ic.fastGuardedObject = NULL;
ic.hasJsFunCheck = false;
}
}
void
JITScript::sweepCallICs(JSContext *cx, bool purgeAll)
{
Repatcher repatcher(this);
/*
* If purgeAll is set, purge stubs in the script except those covered by PurgePICs
* (which is always called during GC). We want to remove references which can keep
* alive pools that we are trying to destroy (see JSCompartment::sweep).
*/
ic::CallICInfo *callICs_ = callICs();
for (uint32 i = 0; i < nCallICs; i++) {
ic::CallICInfo &ic = callICs_[i];
/*
* If the object is unreachable, we're guaranteed not to be currently
* executing a stub generated by a guard on that object. This lets us
* precisely GC call ICs while keeping the identity guard safe.
*/
bool fastFunDead = ic.fastGuardedObject &&
(purgeAll || IsAboutToBeFinalized(cx, ic.fastGuardedObject));
bool hasNative = ic.fastGuardedNative != NULL;
/*
* There are three conditions where we need to relink:
* (1) purgeAll is true.
* (2) There is a native stub. These have a NativeCallStub, which will
* all be released if the compartment has no code on the stack.
* (3) The fastFun is dead *and* there is a closure stub.
*
* Note although both objects can be non-NULL, there can only be one
* of [closure, native] stub per call IC.
*/
if (purgeAll || hasNative || (fastFunDead && ic.hasJsFunCheck)) {
repatcher.relink(ic.funJump, ic.slowPathStart);
ic.hit = false;
}
if (fastFunDead) {
repatcher.repatch(ic.funGuard, NULL);
ic.purgeGuardedObject();
}
if (hasNative)
ic.fastGuardedNative = NULL;
if (purgeAll) {
ic.releasePool(CallICInfo::Pool_ScriptStub);
JSC::CodeLocationJump oolJump = ic.slowPathStart.jumpAtOffset(ic.oolJumpOffset);
JSC::CodeLocationLabel icCall = ic.slowPathStart.labelAtOffset(ic.icCallOffset);
repatcher.relink(oolJump, icCall);
}
}
/* The arguments type check IC can refer to type objects which might be swept. */
if (argsCheckPool)
resetArgsCheck();
if (purgeAll) {
/* Purge ICs generating stubs into execPools. */
uint32 released = 0;
ic::EqualityICInfo *equalityICs_ = equalityICs();
for (uint32 i = 0; i < nEqualityICs; i++) {
ic::EqualityICInfo &ic = equalityICs_[i];
if (!ic.generated)
continue;
JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, ic::Equality));
repatcher.relink(ic.stubCall, fptr);
repatcher.relink(ic.jumpToStub, ic.stubEntry);
ic.generated = false;
released++;
}
ic::SetGlobalNameIC *setGlobalNames_ = setGlobalNames();
for (uint32 i = 0; i < nSetGlobalNames; i ++) {
ic::SetGlobalNameIC &ic = setGlobalNames_[i];
if (!ic.hasExtraStub)
continue;
repatcher.relink(ic.fastPathStart.jumpAtOffset(ic.inlineShapeJump), ic.slowPathStart);
ic.hasExtraStub = false;
released++;
}
JS_ASSERT(released == execPools.length());
for (uint32 i = 0; i < released; i++)
execPools[i]->release();
execPools.clear();
}
}
void
ic::SweepCallICs(JSContext *cx, JSScript *script, bool purgeAll)
{
if (script->jitNormal)
script->jitNormal->sweepCallICs(cx, purgeAll);
if (script->jitCtor)
script->jitCtor->sweepCallICs(cx, purgeAll);
}
#endif /* JS_MONOIC */

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

@ -160,30 +160,6 @@ struct SetGlobalNameIC : public GlobalNameIC
void patchExtraShapeGuard(Repatcher &repatcher, int32 shape);
};
struct TraceICInfo {
TraceICInfo() {}
JSC::CodeLocationLabel stubEntry;
JSC::CodeLocationLabel fastTarget;
JSC::CodeLocationLabel slowTarget;
JSC::CodeLocationJump traceHint;
JSC::CodeLocationJump slowTraceHint;
#ifdef DEBUG
jsbytecode *jumpTargetPC;
#endif
/* This data is used by the tracing JIT. */
void *traceData;
uintN traceEpoch;
uint32 loopCounter;
uint32 loopCounterStart;
bool initialized : 1;
bool hasSlowTraceHint : 1;
};
static const uint16 BAD_TRACEIC_INDEX = (uint16)0xffff;
void JS_FASTCALL GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic);
void JS_FASTCALL SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic);
@ -301,9 +277,6 @@ JSBool JS_FASTCALL SplatApplyArgs(VMFrame &f);
void GenerateArgumentCheckStub(VMFrame &f);
void PurgeMICs(JSContext *cx, JSScript *script);
void SweepCallICs(JSContext *cx, JSScript *script, bool purgeAll);
} /* namespace ic */
} /* namespace mjit */
} /* namespace js */

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

@ -3242,57 +3242,5 @@ ic::SetElement(VMFrame &f, ic::SetElementIC *ic)
template void JS_FASTCALL ic::SetElement<true>(VMFrame &f, SetElementIC *ic);
template void JS_FASTCALL ic::SetElement<false>(VMFrame &f, SetElementIC *ic);
void
JITScript::purgePICs()
{
if (!nPICs && !nGetElems && !nSetElems)
return;
Repatcher repatcher(this);
ic::PICInfo *pics_ = pics();
for (uint32 i = 0; i < nPICs; i++) {
ic::PICInfo &pic = pics_[i];
switch (pic.kind) {
case ic::PICInfo::SET:
case ic::PICInfo::SETMETHOD:
SetPropCompiler::reset(repatcher, pic);
break;
case ic::PICInfo::NAME:
case ic::PICInfo::XNAME:
case ic::PICInfo::CALLNAME:
ScopeNameCompiler::reset(repatcher, pic);
break;
case ic::PICInfo::BIND:
BindNameCompiler::reset(repatcher, pic);
break;
case ic::PICInfo::CALL: /* fall-through */
case ic::PICInfo::GET:
GetPropCompiler::reset(repatcher, pic);
break;
default:
JS_NOT_REACHED("Unhandled PIC kind");
break;
}
pic.reset();
}
ic::GetElementIC *getElems_ = getElems();
ic::SetElementIC *setElems_ = setElems();
for (uint32 i = 0; i < nGetElems; i++)
getElems_[i].purge(repatcher);
for (uint32 i = 0; i < nSetElems; i++)
setElems_[i].purge(repatcher);
}
void
ic::PurgePICs(JSContext *cx, JSScript *script)
{
if (script->jitNormal)
script->jitNormal->purgePICs();
if (script->jitCtor)
script->jitCtor->purgePICs();
}
#endif /* JS_POLYIC */

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

@ -60,8 +60,6 @@ namespace ic {
static const uint32 MAX_PIC_STUBS = 16;
static const uint32 MAX_GETELEM_IC_STUBS = 17;
void PurgePICs(JSContext *cx);
enum LookupStatus {
Lookup_Error = 0,
Lookup_Uncacheable,
@ -554,7 +552,6 @@ struct PICInfo : public BasePolyIC {
};
#ifdef JS_POLYIC
void PurgePICs(JSContext *cx, JSScript *script);
void JS_FASTCALL GetProp(VMFrame &f, ic::PICInfo *);
void JS_FASTCALL GetPropNoCache(VMFrame &f, ic::PICInfo *);
void JS_FASTCALL SetProp(VMFrame &f, ic::PICInfo *);

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

@ -113,11 +113,6 @@ void UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr);
void JS_FASTCALL CreateThis(VMFrame &f, JSObject *proto);
void JS_FASTCALL Throw(VMFrame &f);
#if JS_MONOIC
void * JS_FASTCALL InvokeTracer(VMFrame &f, ic::TraceICInfo *tic);
#else
void * JS_FASTCALL InvokeTracer(VMFrame &f);
#endif
void * JS_FASTCALL LookupSwitch(VMFrame &f, jsbytecode *pc);
void * JS_FASTCALL TableSwitch(VMFrame &f, jsbytecode *origPc);

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

@ -1562,9 +1562,7 @@ ValueToScript(JSContext *cx, jsval v, JSFunction **funp = NULL)
JSObject *obj = JSVAL_TO_OBJECT(v);
JSClass *clasp = JS_GET_CLASS(cx, obj);
if (clasp == Jsvalify(&ScriptClass)) {
script = (JSScript *) JS_GetPrivate(cx, obj);
} else if (clasp == Jsvalify(&GeneratorClass)) {
if (clasp == Jsvalify(&GeneratorClass)) {
JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
fun = gen->floatingFrame()->fun();
script = fun->script();
@ -1624,8 +1622,7 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
v = argv[0];
intarg = 0;
if (!JSVAL_IS_PRIMITIVE(v) &&
(JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&FunctionClass) ||
JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&ScriptClass))) {
JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&FunctionClass)) {
script = ValueToScript(cx, v);
if (!script)
return JS_FALSE;

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

@ -58,3 +58,4 @@ require-or(debugMode,skip) script regress-672804-2.js
require-or(debugMode,skip) script regress-672804-3.js
skip-if(!xulRuntime.shell) script regress-677589.js
script regress-677924.js
script regress-691746.js

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

@ -0,0 +1,11 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
var obj = {};
try {
obj.watch(QName(), function () {});
} catch (exc) {
}
gc();
reportCompare(0, 0, 'ok');

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