зеркало из https://github.com/mozilla/pjs.git
merge from mozilla-central
This commit is contained in:
Коммит
7e6de06af3
|
@ -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');
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче