Merge inbound to m-c a=merge

This commit is contained in:
Wes Kocher 2014-07-01 16:42:57 -07:00
commit 2c447c3198
110 changed files with 2383 additions and 856 deletions

View File

@ -132,6 +132,24 @@ function injectLoopAPI(targetWindow) {
}
},
/**
* Set any character preference under "loop."
*
* @param {String} prefName The name of the pref without the preceding "loop."
* @param {String} stringValue The value to set.
*
* Any errors thrown by the Mozilla pref API are logged to the console
* and cause false to be returned.
*/
setLoopCharPref: {
enumerable: true,
configurable: true,
writable: true,
value: function(prefName, value) {
MozLoopService.setLoopCharPref(prefName, value);
}
},
/**
* Return any preference under "loop." that's coercible to a character
* preference.

View File

@ -443,6 +443,23 @@ this.MozLoopService = {
}
},
/**
* Set any character preference under "loop.".
*
* @param {String} prefName The name of the pref without the preceding "loop."
* @param {String} value The value to set.
*
* Any errors thrown by the Mozilla pref API are logged to the console.
*/
setLoopCharPref: function(prefName, value) {
try {
Services.prefs.setCharPref("loop." + prefName, value);
} catch (ex) {
console.log("setLoopCharPref had trouble setting " + prefName +
"; exception: " + ex);
}
},
/**
* Return any preference under "loop." that's coercible to a character
* preference.

View File

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global XPCOMUtils, Services, Assert */
var fakePrefName = "color";
var fakePrefValue = "green";
function test_setLoopCharPref()
{
Services.prefs.setCharPref("loop." + fakePrefName, "red");
MozLoopService.setLoopCharPref(fakePrefName, fakePrefValue);
var returnedPref = Services.prefs.getCharPref("loop." + fakePrefName);
Assert.equal(returnedPref, fakePrefValue,
"Should set a char pref under the loop. branch");
Services.prefs.clearUserPref("loop." + fakePrefName);
}
function test_setLoopCharPref_new()
{
Services.prefs.clearUserPref("loop." + fakePrefName);
MozLoopService.setLoopCharPref(fakePrefName, fakePrefValue);
var returnedPref = Services.prefs.getCharPref("loop." + fakePrefName);
Assert.equal(returnedPref, fakePrefValue,
"Should set a new char pref under the loop. branch");
Services.prefs.clearUserPref("loop." + fakePrefName);
}
function test_setLoopCharPref_non_coercible_type()
{
MozLoopService.setLoopCharPref(fakePrefName, true);
ok(true, "Setting non-coercible type should not fail");
}
function run_test()
{
test_setLoopCharPref();
test_setLoopCharPref_new();
test_setLoopCharPref_non_coercible_type();
do_register_cleanup(function() {
Services.prefs.clearUserPref("loop." + fakePrefName);
});
}

View File

@ -7,6 +7,7 @@ firefox-appdir = browser
[test_loopservice_dnd.js]
[test_loopservice_expiry.js]
[test_loopservice_get_loop_char_pref.js]
[test_loopservice_set_loop_char_pref.js]
[test_loopservice_initialize.js]
[test_loopservice_locales.js]
[test_loopservice_registration.js]

View File

@ -10,7 +10,6 @@ PARALLEL_DIRS += [
'dirprovider',
'downloads',
'feeds',
'loop',
'places',
'preferences',
'privatebrowsing',
@ -23,6 +22,9 @@ PARALLEL_DIRS += [
'migration',
]
if CONFIG['MOZ_LOOP']:
PARALLEL_DIRS += ['loop']
DIRS += ['build']
XPIDL_SOURCES += [

View File

@ -65,6 +65,7 @@ elif os == 'Android':
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
gyp_vars['build_with_gonk'] = 1
gyp_vars['moz_widget_toolkit_gonk'] = 1
gyp_vars['opus_complexity'] = 1
if int(CONFIG['ANDROID_VERSION']) >= 18:
gyp_vars['moz_webrtc_omx'] = 1
else:

View File

@ -478,16 +478,19 @@ Element::WrapObject(JSContext *aCx)
return nullptr;
}
nsRefPtr<nsXBLBinding> binding;
xblService->LoadBindings(this, uri, principal, getter_AddRefs(binding), &dummy);
if (binding) {
if (nsContentUtils::IsSafeToRunScript()) {
binding->ExecuteAttachedHandler();
}
else {
nsContentUtils::AddScriptRunner(
NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
{
// Make a scope so that ~nsRefPtr can GC before returning obj.
nsRefPtr<nsXBLBinding> binding;
xblService->LoadBindings(this, uri, principal, getter_AddRefs(binding), &dummy);
if (binding) {
if (nsContentUtils::IsSafeToRunScript()) {
binding->ExecuteAttachedHandler();
}
else {
nsContentUtils::AddScriptRunner(
NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
}
}
}

View File

@ -157,7 +157,7 @@ FileIOObject::OnInputStreamReady(nsIAsyncInputStream* aStream)
rv = DoAsyncWait(aStream);
}
if (!aCount || NS_FAILED(rv)) {
if (NS_FAILED(rv) || !aCount) {
if (rv == NS_BASE_STREAM_CLOSED) {
rv = NS_OK;
}

View File

@ -1535,13 +1535,15 @@ nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
JS::Rooted<JSObject*> funobj(cx);
if (aRunInGlobalScope) {
options.setNoScriptRval(true);
script = JS::Compile(cx, JS::NullPtr(), options, srcBuf);
if (!JS::Compile(cx, JS::NullPtr(), options, srcBuf, &script)) {
return;
}
} else {
JS::Rooted<JSFunction *> fun(cx);
fun = JS::CompileFunction(cx, JS::NullPtr(), options,
nullptr, 0, nullptr, /* name, nargs, args */
srcBuf);
if (!fun) {
if (!JS::CompileFunction(cx, JS::NullPtr(), options,
nullptr, 0, nullptr, /* name, nargs, args */
srcBuf, &fun))
{
return;
}
funobj = JS_GetFunctionObject(fun);

View File

@ -21,13 +21,13 @@ class EncodingCompleteEvent : public nsRunnable
public:
NS_DECL_THREADSAFE_ISUPPORTS
EncodingCompleteEvent(nsIScriptContext* aScriptContext,
EncodingCompleteEvent(nsIGlobalObject* aGlobal,
nsIThread* aEncoderThread,
FileCallback& aCallback)
: mImgSize(0)
, mType()
, mImgData(nullptr)
, mScriptContext(aScriptContext)
, mGlobal(aGlobal)
, mEncoderThread(aEncoderThread)
, mCallback(&aCallback)
, mFailed(false)
@ -43,11 +43,10 @@ public:
nsRefPtr<DOMFile> blob =
DOMFile::CreateMemoryFile(mImgData, mImgSize, mType);
if (mScriptContext) {
JSContext* jsContext = mScriptContext->GetNativeContext();
if (jsContext) {
JS_updateMallocCounter(jsContext, mImgSize);
}
{
AutoJSAPI jsapi;
jsapi.Init(mGlobal);
JS_updateMallocCounter(jsapi.cx(), mImgSize);
}
mCallback->Call(blob, rv);
@ -57,7 +56,7 @@ public:
// released on the main thread here. Otherwise, they could be getting
// released by EncodingRunnable's destructor on the encoding thread
// (bug 916128).
mScriptContext = nullptr;
mGlobal = nullptr;
mCallback = nullptr;
mEncoderThread->Shutdown();
@ -80,7 +79,7 @@ private:
uint64_t mImgSize;
nsAutoString mType;
void* mImgData;
nsCOMPtr<nsIScriptContext> mScriptContext;
nsCOMPtr<nsIGlobalObject> mGlobal;
nsCOMPtr<nsIThread> mEncoderThread;
nsRefPtr<FileCallback> mCallback;
bool mFailed;
@ -209,9 +208,11 @@ ImageEncoder::ExtractDataAsync(nsAString& aType,
int32_t aFormat,
const nsIntSize aSize,
nsICanvasRenderingContextInternal* aContext,
nsIScriptContext* aScriptContext,
nsIGlobalObject* aGlobal,
FileCallback& aCallback)
{
MOZ_ASSERT(aGlobal);
nsCOMPtr<imgIEncoder> encoder = ImageEncoder::GetImageEncoder(aType);
if (!encoder) {
return NS_IMAGELIB_ERROR_NO_ENCODER;
@ -222,7 +223,7 @@ ImageEncoder::ExtractDataAsync(nsAString& aType,
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<EncodingCompleteEvent> completeEvent =
new EncodingCompleteEvent(aScriptContext, encoderThread, aCallback);
new EncodingCompleteEvent(aGlobal, encoderThread, aCallback);
nsCOMPtr<nsIRunnable> event = new EncodingRunnable(aType,
aOptions,

View File

@ -15,6 +15,7 @@
#include "nsSize.h"
class nsICanvasRenderingContextInternal;
class nsIGlobalObject;
namespace mozilla {
namespace dom {
@ -50,7 +51,7 @@ public:
int32_t aFormat,
const nsIntSize aSize,
nsICanvasRenderingContextInternal* aContext,
nsIScriptContext* aScriptContext,
nsIGlobalObject* aGlobal,
FileCallback& aCallback);
// Gives you a stream containing the image represented by aImageBuffer.
@ -89,4 +90,4 @@ private:
} // namespace dom
} // namespace mozilla
#endif // ImageEncoder_h
#endif // ImageEncoder_h

View File

@ -543,15 +543,14 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
}
#endif
nsCOMPtr<nsIScriptContext> scriptContext =
GetScriptContextFromJSContext(nsContentUtils::GetCurrentJSContext());
uint8_t* imageBuffer = nullptr;
int32_t format = 0;
if (mCurrentContext) {
mCurrentContext->GetImageBuffer(&imageBuffer, &format);
}
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
MOZ_ASSERT(global);
aRv = ImageEncoder::ExtractDataAsync(type,
params,
usingCustomParseOptions,
@ -559,7 +558,7 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
format,
GetSize(),
mCurrentContext,
scriptContext,
global,
aCallback);
}

View File

@ -53,7 +53,7 @@ nsresult
MediaEngineTabVideoSource::StopRunnable::Run()
{
nsCOMPtr<nsPIDOMWindow> privateDOMWindow = do_QueryInterface(mVideoSource->mWindow);
if (privateDOMWindow && mVideoSource && privateDOMWindow->GetChromeEventHandler()) {
if (privateDOMWindow && privateDOMWindow->GetChromeEventHandler()) {
privateDOMWindow->GetChromeEventHandler()->RemoveEventListener(NS_LITERAL_STRING("MozAfterPaint"), mVideoSource, false);
}
@ -284,6 +284,9 @@ MediaEngineTabVideoSource::Draw() {
nsresult
MediaEngineTabVideoSource::Stop(mozilla::SourceMediaStream*, mozilla::TrackID)
{
if (!mWindow)
return NS_OK;
NS_DispatchToMainThread(new StopRunnable(this));
return NS_OK;
}

View File

@ -2762,8 +2762,8 @@ nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf,
// This reference will be consumed by the NotifyOffThreadScriptCompletedRunnable.
NS_ADDREF(aOffThreadReceiver);
} else {
JSScript* script = JS::Compile(cx, scope, options, aSrcBuf);
if (!script)
JS::Rooted<JSScript*> script(cx);
if (!JS::Compile(cx, scope, options, aSrcBuf, &script))
return NS_ERROR_OUT_OF_MEMORY;
Set(script);
}

View File

@ -232,10 +232,16 @@ AutoJSAPI::InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread)
{
mCx = aCx;
if (aIsMainThread) {
// This Rooted<> is necessary only as long as AutoCxPusher::AutoCxPusher
// can GC, which is only possible because XPCJSContextStack::Push calls
// nsIPrincipal.Equals. Once that is removed, the Rooted<> will no longer
// be necessary.
JS::Rooted<JSObject*> global(JS_GetRuntime(aCx), aGlobal);
mCxPusher.construct(mCx);
mAutoNullableCompartment.construct(mCx, global);
} else {
mAutoNullableCompartment.construct(mCx, aGlobal);
}
mAutoNullableCompartment.construct(mCx, aGlobal);
}
AutoJSAPI::AutoJSAPI(nsIGlobalObject* aGlobalObject,

View File

@ -2802,23 +2802,33 @@ NS_DOMReadStructuredClone(JSContext* cx,
}
MOZ_ASSERT(dataArray.isObject());
// Construct the ImageData.
nsRefPtr<ImageData> imageData = new ImageData(width, height,
dataArray.toObject());
// Wrap it in a JS::Value.
return imageData->WrapObject(cx);
// Protect the result from a moving GC in ~nsRefPtr.
JS::Rooted<JSObject*> result(cx);
{
// Construct the ImageData.
nsRefPtr<ImageData> imageData = new ImageData(width, height,
dataArray.toObject());
// Wrap it in a JS::Value.
result = imageData->WrapObject(cx);
}
return result;
} else if (tag == SCTAG_DOM_WEBCRYPTO_KEY) {
nsIGlobalObject *global = xpc::GetNativeForGlobal(JS::CurrentGlobalOrNull(cx));
if (!global) {
return nullptr;
}
nsRefPtr<Key> key = new Key(global);
if (!key->ReadStructuredClone(reader)) {
return nullptr;
// Prevent the return value from being trashed by a GC during ~nsRefPtr.
JS::Rooted<JSObject*> result(cx);
{
nsRefPtr<Key> key = new Key(global);
if (!key->ReadStructuredClone(reader)) {
result = nullptr;
} else {
result = key->WrapObject(cx);
}
}
return key->WrapObject(cx);
return result;
}
// Don't know what this is. Bail.

View File

@ -157,12 +157,13 @@ nsJSUtils::CompileFunction(JSContext* aCx,
}
// Compile.
JSFunction* fun = JS::CompileFunction(aCx, aTarget, aOptions,
PromiseFlatCString(aName).get(),
aArgCount, aArgArray,
PromiseFlatString(aBody).get(),
aBody.Length());
if (!fun) {
JS::Rooted<JSFunction*> fun(aCx);
if (!JS::CompileFunction(aCx, aTarget, aOptions,
PromiseFlatCString(aName).get(),
aArgCount, aArgArray,
PromiseFlatString(aBody).get(),
aBody.Length(), &fun))
{
ReportPendingException(aCx);
return NS_ERROR_FAILURE;
}

View File

@ -1598,17 +1598,19 @@ class CGConstructNavigatorObject(CGAbstractMethod):
return nullptr;
}
ErrorResult rv;
nsRefPtr<mozilla::dom::${descriptorName}> result = ConstructNavigatorObjectHelper(aCx, global, rv);
rv.WouldReportJSException();
if (rv.Failed()) {
ThrowMethodFailedWithDetails(aCx, rv, "${descriptorName}", "navigatorConstructor");
return nullptr;
}
JS::Rooted<JS::Value> v(aCx);
if (!WrapNewBindingObject(aCx, result, &v)) {
//XXX Assertion disabled for now, see bug 991271.
MOZ_ASSERT(true || JS_IsExceptionPending(aCx));
return nullptr;
{ // Scope to make sure |result| goes out of scope while |v| is rooted
nsRefPtr<mozilla::dom::${descriptorName}> result = ConstructNavigatorObjectHelper(aCx, global, rv);
rv.WouldReportJSException();
if (rv.Failed()) {
ThrowMethodFailedWithDetails(aCx, rv, "${descriptorName}", "navigatorConstructor");
return nullptr;
}
if (!WrapNewBindingObject(aCx, result, &v)) {
//XXX Assertion disabled for now, see bug 991271.
MOZ_ASSERT(true || JS_IsExceptionPending(aCx));
return nullptr;
}
}
return &v.toObject();
""",

View File

@ -72,8 +72,8 @@ DeviceStorageRequestChild::
nsString fullPath;
mDSFile->GetFullPath(fullPath);
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx,
StringToJsval(mRequest->GetOwner(), fullPath));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), fullPath, &result);
mRequest->FireSuccess(result);
break;
}
@ -85,8 +85,8 @@ DeviceStorageRequestChild::
nsString fullPath;
mDSFile->GetFullPath(fullPath);
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx,
StringToJsval(mRequest->GetOwner(), fullPath));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), fullPath, &result);
mDSFileDescriptor->mDSFile = mDSFile;
mDSFileDescriptor->mFileDescriptor = r.fileDescriptor();
@ -130,8 +130,8 @@ DeviceStorageRequestChild::
{
AvailableStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(
cx, StringToJsval(mRequest->GetOwner(), r.mountState()));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), r.mountState(), &result);
mRequest->FireSuccess(result);
break;
}
@ -140,8 +140,8 @@ DeviceStorageRequestChild::
{
StorageStatusResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(
cx, StringToJsval(mRequest->GetOwner(), r.storageStatus()));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), r.storageStatus(), &result);
mRequest->FireSuccess(result);
break;
}
@ -150,8 +150,8 @@ DeviceStorageRequestChild::
{
FormatStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(
cx, StringToJsval(mRequest->GetOwner(), r.mountState()));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), r.mountState(), &result);
mRequest->FireSuccess(result);
break;
}
@ -160,8 +160,8 @@ DeviceStorageRequestChild::
{
MountStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(
cx, StringToJsval(mRequest->GetOwner(), r.storageStatus()));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), r.storageStatus(), &result);
mRequest->FireSuccess(result);
break;
}
@ -170,8 +170,8 @@ DeviceStorageRequestChild::
{
UnmountStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(
cx, StringToJsval(mRequest->GetOwner(), r.storageStatus()));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), r.storageStatus(), &result);
mRequest->FireSuccess(result);
break;
}

View File

@ -1669,21 +1669,27 @@ InterfaceToJsval(nsPIDOMWindow* aWindow,
nsISupports* aObject,
const nsIID* aIID)
{
AutoJSContext cx;
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow);
if (!sgo) {
return JSVAL_NULL;
return JS::NullValue();
}
JS::Rooted<JSObject*> scopeObj(cx, sgo->GetGlobalJSObject());
NS_ENSURE_TRUE(scopeObj, JSVAL_NULL);
JSAutoCompartment ac(cx, scopeObj);
JSObject *unrootedScopeObj = sgo->GetGlobalJSObject();
NS_ENSURE_TRUE(unrootedScopeObj, JS::NullValue());
JSRuntime *runtime = JS_GetObjectRuntime(unrootedScopeObj);
JS::Rooted<JS::Value> someJsVal(runtime);
nsresult rv;
{ // Protect someJsVal from moving GC in ~JSAutoCompartment
AutoJSContext cx;
JS::Rooted<JS::Value> someJsVal(cx);
nsresult rv = nsContentUtils::WrapNative(cx, aObject, aIID, &someJsVal);
JS::Rooted<JSObject*> scopeObj(cx, unrootedScopeObj);
JSAutoCompartment ac(cx, scopeObj);
rv = nsContentUtils::WrapNative(cx, aObject, aIID, &someJsVal);
}
if (NS_FAILED(rv)) {
return JSVAL_NULL;
return JS::NullValue();
}
return someJsVal;
@ -1720,23 +1726,24 @@ nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile)
return InterfaceToJsval(aWindow, blob, &NS_GET_IID(nsIDOMBlob));
}
JS::Value StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString)
bool
StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString,
JS::MutableHandle<JS::Value> result)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWindow);
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(aWindow))) {
return JSVAL_NULL;
return false;
}
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> result(cx);
if (!xpc::StringToJsval(cx, aString, &result)) {
return JSVAL_NULL;
if (!xpc::StringToJsval(cx, aString, result)) {
return false;
}
return result;
return true;
}
class DeviceStorageCursorRequest MOZ_FINAL
@ -2135,8 +2142,8 @@ public:
}
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx,
StringToJsval(mRequest->GetOwner(), state));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), state, &result);
mRequest->FireSuccess(result);
mRequest = nullptr;
return NS_OK;
@ -2169,8 +2176,8 @@ public:
}
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx,
StringToJsval(mRequest->GetOwner(), state));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), state, &result);
mRequest->FireSuccess(result);
mRequest = nullptr;
return NS_OK;
@ -2203,8 +2210,8 @@ public:
}
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx,
StringToJsval(mRequest->GetOwner(), state));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), state, &result);
mRequest->FireSuccess(result);
mRequest = nullptr;
return NS_OK;
@ -2237,8 +2244,8 @@ public:
}
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx,
StringToJsval(mRequest->GetOwner(), state));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), state, &result);
mRequest->FireSuccess(result);
mRequest = nullptr;
return NS_OK;
@ -2271,8 +2278,8 @@ public:
}
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx,
StringToJsval(mRequest->GetOwner(), state));
JS::Rooted<JS::Value> result(cx);
StringToJsval(mRequest->GetOwner(), state, &result);
mRequest->FireSuccess(result);
mRequest = nullptr;
return NS_OK;
@ -2323,7 +2330,7 @@ public:
if (mFile) {
result = nsIFileToJsval(window, mFile);
} else if (mPath.Length()) {
result = StringToJsval(window, mPath);
StringToJsval(window, mPath, &result);
}
else {
result = JS_NumberValue(double(mValue));

View File

@ -228,8 +228,9 @@ private:
};
//helpers
JS::Value
StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString);
bool
StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString,
JS::MutableHandle<JS::Value> result);
JS::Value
nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile);

View File

@ -12,6 +12,7 @@
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/ErrorEventBinding.h"
#include "mozilla/dom/IDBOpenDBRequestBinding.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/UnionTypes.h"
#include "nsComponentManagerUtils.h"
#include "nsDOMClassInfoID.h"
@ -188,18 +189,24 @@ IDBRequest::NotifyHelperCompleted(HelperBase* aHelper)
}
// Otherwise we need to get the result from the helper.
AutoPushJSContext cx(GetJSContext());
if (!cx) {
IDB_WARNING("Failed to get safe JSContext!");
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
SetError(rv);
return rv;
AutoJSAPI jsapi;
Maybe<JSAutoCompartment> ac;
if (GetScriptOwner()) {
// If we have a script owner we want the SafeJSContext and then to enter
// the script owner's compartment.
jsapi.Init();
ac.construct(jsapi.cx(), GetScriptOwner());
} else {
// Otherwise our owner is a window and we use that to initialize.
if (!jsapi.InitWithLegacyErrorReporting(GetOwner())) {
IDB_WARNING("Failed to initialise AutoJSAPI!");
rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
SetError(rv);
return rv;
}
}
JSContext* cx = jsapi.cx();
JS::Rooted<JSObject*> global(cx, IDBWrapperCache::GetParentObject());
NS_ASSERTION(global, "This should never be null!");
JSAutoCompartment ac(cx, global);
AssertIsRooted();
JS::Rooted<JS::Value> value(cx);
@ -263,28 +270,6 @@ IDBRequest::GetErrorCode() const
}
#endif
JSContext*
IDBRequest::GetJSContext()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
JSContext* cx;
if (GetScriptOwner()) {
return nsContentUtils::GetSafeJSContext();
}
nsresult rv;
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
NS_ENSURE_SUCCESS(rv, nullptr);
NS_ENSURE_TRUE(sc, nullptr);
cx = sc->GetNativeContext();
NS_ASSERTION(cx, "Failed to get a context!");
return cx;
}
void
IDBRequest::CaptureCaller()
{

View File

@ -86,8 +86,6 @@ public:
DOMError* GetError(ErrorResult& aRv);
JSContext* GetJSContext();
void
SetActor(IndexedDBRequestParentBase* aActorParent)
{

View File

@ -26,19 +26,6 @@ public:
}
void SetScriptOwner(JSObject* aScriptOwner);
JSObject* GetParentObject()
{
if (mScriptOwner) {
return mScriptOwner;
}
// Do what nsEventTargetSH::PreCreate does.
nsCOMPtr<nsIScriptGlobalObject> parent;
DOMEventTargetHelper::GetParentObject(getter_AddRefs(parent));
return parent ? parent->GetGlobalJSObject() : nullptr;
}
#ifdef DEBUG
void AssertIsRooted() const;
#else

View File

@ -12,6 +12,7 @@
#include "nsIScriptGlobalObject.h"
#include "nsPIDOMWindow.h"
#include "MmsMessage.h"
#include "mozilla/dom/ScriptSettings.h"
#include "jsapi.h"
#include "xpcpublic.h"
#include "nsServiceManagerUtils.h"
@ -103,21 +104,14 @@ MobileMessageCallback::NotifySuccess(JS::Handle<JS::Value> aResult, bool aAsync)
nsresult
MobileMessageCallback::NotifySuccess(nsISupports *aMessage, bool aAsync)
{
nsresult rv;
nsIScriptContext* scriptContext = mDOMRequest->GetContextForEventHandlers(&rv);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
AutoPushJSContext cx(scriptContext->GetNativeContext());
NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
JS::Rooted<JSObject*> global(cx, scriptContext->GetWindowProxy());
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
JSAutoCompartment ac(cx, global);
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mDOMRequest->GetOwner()))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> wrappedMessage(cx);
rv = nsContentUtils::WrapNative(cx, aMessage, &wrappedMessage);
nsresult rv = nsContentUtils::WrapNative(cx, aMessage, &wrappedMessage);
NS_ENSURE_SUCCESS(rv, rv);
return NotifySuccess(wrappedMessage, aAsync);
@ -196,16 +190,13 @@ MobileMessageCallback::NotifyMessageDeleted(bool *aDeleted, uint32_t aSize)
return NotifySuccess(val);
}
nsresult rv;
nsIScriptContext* sc = mDOMRequest->GetContextForEventHandlers(&rv);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(sc, NS_ERROR_FAILURE);
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mDOMRequest->GetOwner()))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
AutoPushJSContext cx(sc->GetNativeContext());
NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
JS::Rooted<JSObject*> deleteArrayObj(cx,
JS_NewArrayObject(cx, aSize));
JS::Rooted<JSObject*> deleteArrayObj(cx, JS_NewArrayObject(cx, aSize));
for (uint32_t i = 0; i < aSize; i++) {
JS_SetElement(cx, deleteArrayObj, i, aDeleted[i]);
}

View File

@ -4,11 +4,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MobileMessageCursorCallback.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsIDOMDOMRequest.h"
#include "nsIDOMMozSmsMessage.h"
#include "nsIMobileMessageCallback.h"
#include "DOMCursor.h"
#include "nsCxPusher.h"
#include "nsServiceManagerUtils.h" // for do_GetService
namespace mozilla {
@ -59,21 +59,14 @@ MobileMessageCursorCallback::NotifyCursorResult(nsISupports* aResult)
{
MOZ_ASSERT(mDOMCursor);
nsresult rv;
nsIScriptContext* scriptContext = mDOMCursor->GetContextForEventHandlers(&rv);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
AutoPushJSContext cx(scriptContext->GetNativeContext());
NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
JS::Rooted<JSObject*> global(cx, scriptContext->GetWindowProxy());
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
JSAutoCompartment ac(cx, global);
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mDOMCursor->GetOwner()))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> wrappedResult(cx);
rv = nsContentUtils::WrapNative(cx, aResult, &wrappedResult);
nsresult rv = nsContentUtils::WrapNative(cx, aResult, &wrappedResult);
NS_ENSURE_SUCCESS(rv, rv);
mDOMCursor->FireSuccess(wrappedResult);

View File

@ -41,6 +41,7 @@
#include "nsWildCard.h"
#include "nsContentUtils.h"
#include "nsCxPusher.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsIXPConnect.h"
@ -643,27 +644,6 @@ GetDocumentFromNPP(NPP npp)
return doc;
}
static JSContext *
GetJSContextFromDoc(nsIDocument *doc)
{
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(doc->GetWindow());
NS_ENSURE_TRUE(sgo, nullptr);
nsIScriptContext *scx = sgo->GetContext();
NS_ENSURE_TRUE(scx, nullptr);
return scx->GetNativeContext();
}
static JSContext *
GetJSContextFromNPP(NPP npp)
{
nsIDocument *doc = GetDocumentFromNPP(npp);
NS_ENSURE_TRUE(doc, nullptr);
return GetJSContextFromDoc(doc);
}
static already_AddRefed<nsIChannel>
GetChannelFromNPP(NPP npp)
{
@ -1239,9 +1219,16 @@ _getpluginelement(NPP npp)
if (!element)
return nullptr;
AutoPushJSContext cx(GetJSContextFromNPP(npp));
NS_ENSURE_TRUE(cx, nullptr);
JSAutoRequest ar(cx); // Unnecessary once bug 868130 lands.
nsIDocument *doc = GetDocumentFromNPP(npp);
if (NS_WARN_IF(!doc)) {
return nullptr;
}
dom::AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(doc->GetInnerWindow()))) {
return nullptr;
}
JSContext* cx = jsapi.cx();
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
NS_ENSURE_TRUE(xpc, nullptr);

View File

@ -39,7 +39,7 @@ interface TextTrack : EventTarget {
[Throws]
void removeCue(VTTCue cue);
attribute EventHandler oncuechange;
//(Not implemented)attribute EventHandler oncuechange;
};
// Mozilla Extensions

View File

@ -117,34 +117,37 @@ GetDataStoresStructuredCloneCallbacksRead(JSContext* aCx,
return nullptr;
}
nsRefPtr<WorkerDataStore> workerStore =
new WorkerDataStore(workerPrivate->GlobalScope());
nsMainThreadPtrHandle<DataStore> backingStore = dataStoreholder;
// Protect workerStoreObj from moving GC during ~nsRefPtr.
JS::Rooted<JSObject*> workerStoreObj(aCx, nullptr);
{
nsRefPtr<WorkerDataStore> workerStore =
new WorkerDataStore(workerPrivate->GlobalScope());
nsMainThreadPtrHandle<DataStore> backingStore = dataStoreholder;
// When we're on the worker thread, prepare a DataStoreChangeEventProxy.
nsRefPtr<DataStoreChangeEventProxy> eventProxy =
new DataStoreChangeEventProxy(workerPrivate, workerStore);
// When we're on the worker thread, prepare a DataStoreChangeEventProxy.
nsRefPtr<DataStoreChangeEventProxy> eventProxy =
new DataStoreChangeEventProxy(workerPrivate, workerStore);
// Add the DataStoreChangeEventProxy as an event listener on the main thread.
nsRefPtr<DataStoreAddEventListenerRunnable> runnable =
new DataStoreAddEventListenerRunnable(workerPrivate,
backingStore,
eventProxy);
runnable->Dispatch(aCx);
// Add the DataStoreChangeEventProxy as an event listener on the main thread.
nsRefPtr<DataStoreAddEventListenerRunnable> runnable =
new DataStoreAddEventListenerRunnable(workerPrivate,
backingStore,
eventProxy);
runnable->Dispatch(aCx);
// Point WorkerDataStore to DataStore.
workerStore->SetBackingDataStore(backingStore);
// Point WorkerDataStore to DataStore.
workerStore->SetBackingDataStore(backingStore);
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
if (!global) {
MOZ_ASSERT(false, "cannot get global!");
return nullptr;
}
JS::Rooted<JSObject*> workerStoreObj(aCx, workerStore->WrapObject(aCx));
if (!JS_WrapObject(aCx, &workerStoreObj)) {
MOZ_ASSERT(false, "cannot wrap object for workerStoreObj!");
return nullptr;
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
if (!global) {
MOZ_ASSERT(false, "cannot get global!");
} else {
workerStoreObj = workerStore->WrapObject(aCx);
if (!JS_WrapObject(aCx, &workerStoreObj)) {
MOZ_ASSERT(false, "cannot wrap object for workerStoreObj!");
workerStoreObj = nullptr;
}
}
}
return workerStoreObj;

View File

@ -300,6 +300,8 @@ struct WorkerStructuredCloneCallbacks
Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
uint32_t aData, void* aClosure)
{
JS::Rooted<JSObject*> result(aCx);
// See if object is a nsIDOMFile pointer.
if (aTag == DOMWORKER_SCTAG_FILE) {
MOZ_ASSERT(!aData);
@ -318,9 +320,12 @@ struct WorkerStructuredCloneCallbacks
}
#endif
nsRefPtr<DOMFile> file = new DOMFile(fileImpl);
JSObject* jsFile = file::CreateFile(aCx, file);
return jsFile;
{
// New scope to protect |result| from a moving GC during ~nsRefPtr.
nsRefPtr<DOMFile> file = new DOMFile(fileImpl);
result = file::CreateFile(aCx, file);
}
return result;
}
}
// See if object is a nsIDOMBlob pointer.
@ -341,9 +346,12 @@ struct WorkerStructuredCloneCallbacks
}
#endif
nsRefPtr<DOMFile> blob = new DOMFile(blobImpl);
JSObject* jsBlob = file::CreateBlob(aCx, blob);
return jsBlob;
{
// New scope to protect |result| from a moving GC during ~nsRefPtr.
nsRefPtr<DOMFile> blob = new DOMFile(blobImpl);
result = file::CreateBlob(aCx, blob);
}
return result;
}
}
// See if the object is an ImageData.
@ -360,11 +368,14 @@ struct WorkerStructuredCloneCallbacks
}
MOZ_ASSERT(dataArray.isObject());
// Construct the ImageData.
nsRefPtr<ImageData> imageData = new ImageData(width, height,
dataArray.toObject());
// Wrap it in a JS::Value.
return imageData->WrapObject(aCx);
{
// Construct the ImageData.
nsRefPtr<ImageData> imageData = new ImageData(width, height,
dataArray.toObject());
// Wrap it in a JS::Value, protected from a moving GC during ~nsRefPtr.
result = imageData->WrapObject(aCx);
}
return result;
}
Error(aCx, 0);

View File

@ -165,9 +165,10 @@ Load(JSContext *cx,
JS::CompileOptions options(cx);
options.setUTF8(true)
.setFileAndLine(filename.ptr(), 1);
JS::Rooted<JSScript*> script(cx, JS::Compile(cx, obj, options, file));
JS::Rooted<JSScript*> script(cx);
bool ok = JS::Compile(cx, obj, options, file, &script);
fclose(file);
if (!script)
if (!ok)
return false;
if (!JS_ExecuteScript(cx, obj, script)) {
@ -334,8 +335,8 @@ XPCShellEnvironment::ProcessFile(JSContext *cx,
JS::CompileOptions options(cx);
options.setUTF8(true)
.setFileAndLine(filename, 1);
JS::Rooted<JSScript*> script(cx, JS::Compile(cx, obj, options, file));
if (script)
JS::Rooted<JSScript*> script(cx);
if (JS::Compile(cx, obj, options, file, &script))
(void)JS_ExecuteScript(cx, obj, script, &result);
return;
@ -371,9 +372,8 @@ XPCShellEnvironment::ProcessFile(JSContext *cx,
JS_ClearPendingException(cx);
JS::CompileOptions options(cx);
options.setFileAndLine("typein", startline);
JS::Rooted<JSScript*> script(cx,
JS_CompileScript(cx, obj, buffer, strlen(buffer), options));
if (script) {
JS::Rooted<JSScript*> script(cx);
if (JS_CompileScript(cx, obj, buffer, strlen(buffer), options, &script)) {
JSErrorReporter older;
ok = JS_ExecuteScript(cx, obj, script, &result);
@ -580,9 +580,10 @@ XPCShellEnvironment::EvaluateString(const nsString& aString,
JS::CompileOptions options(cx);
options.setFileAndLine("typein", 0);
JS::Rooted<JSScript*> script(cx, JS_CompileUCScript(cx, global, aString.get(),
aString.Length(), options));
if (!script) {
JS::Rooted<JSScript*> script(cx);
if (!JS_CompileUCScript(cx, global, aString.get(), aString.Length(), options,
&script))
{
return false;
}

View File

@ -21,7 +21,6 @@ using namespace js;
using mozilla::AddToHash;
using mozilla::HashString;
using mozilla::Range;
using mozilla::RangedPtr;
using JS::AutoCheckCannotGC;
@ -151,7 +150,7 @@ enum EvalJSONResult {
template <typename CharT>
static bool
EvalStringMightBeJSON(const Range<const CharT> chars)
EvalStringMightBeJSON(const mozilla::Range<const CharT> chars)
{
// If the eval string starts with '(' or '[' and ends with ')' or ']', it may be JSON.
// Try the JSON parser first because it's much faster. If the eval string
@ -186,7 +185,7 @@ EvalStringMightBeJSON(const Range<const CharT> chars)
template <typename CharT>
static EvalJSONResult
ParseEvalStringAsJSON(JSContext *cx, const Range<const CharT> chars, MutableHandleValue rval)
ParseEvalStringAsJSON(JSContext *cx, const mozilla::Range<const CharT> chars, MutableHandleValue rval)
{
size_t len = chars.length();
MOZ_ASSERT((chars[0] == '(' && chars[len - 1] == ')') ||
@ -194,7 +193,7 @@ ParseEvalStringAsJSON(JSContext *cx, const Range<const CharT> chars, MutableHand
auto jsonChars = (chars[0] == '[')
? chars
: Range<const CharT>(chars.start().get() + 1U, len - 2);
: mozilla::Range<const CharT>(chars.start().get() + 1U, len - 2);
JSONParser<CharT> parser(cx, jsonChars, JSONParserBase::NoError);
if (!parser.parse(rval))
@ -312,7 +311,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
esg.lookupInEvalCache(flatStr, callerScript, pc);
if (!esg.foundScript()) {
JSScript *maybeScript;
RootedScript maybeScript(cx);
unsigned lineno;
const char *filename;
JSPrincipals *originPrincipals;
@ -388,7 +387,7 @@ js::DirectEvalStringFromIon(JSContext *cx,
esg.lookupInEvalCache(flatStr, callerScript, pc);
if (!esg.foundScript()) {
JSScript *maybeScript;
RootedScript maybeScript(cx);
const char *filename;
unsigned lineno;
JSPrincipals *originPrincipals;

View File

@ -45,7 +45,6 @@ using namespace js;
using mozilla::IsFinite;
using mozilla::IsNegativeZero;
using mozilla::Range;
#if ENABLE_INTL_API
using icu::Locale;
@ -974,8 +973,8 @@ intl_CompareStrings(JSContext *cx, UCollator *coll, HandleString str1, HandleStr
if (!stableChars2.initTwoByte(cx, str2))
return false;
Range<const jschar> chars1 = stableChars1.twoByteRange();
Range<const jschar> chars2 = stableChars2.twoByteRange();
mozilla::Range<const jschar> chars1 = stableChars1.twoByteRange();
mozilla::Range<const jschar> chars2 = stableChars2.twoByteRange();
UCollationResult uresult = ucol_strcoll(coll,
JSCharToUChar(chars1.start().get()), chars1.length(),
@ -1800,7 +1799,7 @@ js::intl_patternForSkeleton(JSContext *cx, unsigned argc, Value *vp)
if (!stableChars.initTwoByte(cx, skeletonFlat))
return false;
Range<const jschar> skeletonChars = stableChars.twoByteRange();
mozilla::Range<const jschar> skeletonChars = stableChars.twoByteRange();
uint32_t skeletonLen = u_strlen(JSCharToUChar(skeletonChars.start().get()));
UErrorCode status = U_ZERO_ERROR;

View File

@ -3212,6 +3212,17 @@ if test -n "$JSGC_USE_EXACT_ROOTING"; then
AC_DEFINE(JSGC_USE_EXACT_ROOTING)
fi
dnl ========================================================
dnl = Use GC tracing
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(gc-trace,
[ --enable-gc-trace Enable tracing of allocation and finalization],
JS_GC_TRACE=1,
JS_GC_TRACE= )
if test -n "$JS_GC_TRACE"; then
AC_DEFINE(JS_GC_TRACE)
fi
dnl ========================================================
dnl = Use Valgrind
dnl ========================================================

View File

@ -42,15 +42,18 @@
using namespace std;
using mozilla::NumericLimits;
using JS::AutoCheckCannotGC;
namespace js {
namespace ctypes {
template <typename CharT>
size_t
GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars,
GetDeflatedUTF8StringLength(JSContext *maybecx, const CharT *chars,
size_t nchars)
{
size_t nbytes;
const jschar *end;
const CharT *end;
unsigned c, c2;
char buffer[10];
@ -83,6 +86,7 @@ GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars,
bad_surrogate:
if (maybecx) {
js::gc::AutoSuppressGC suppress(maybecx);
JS_snprintf(buffer, 10, "0x%x", c);
JS_ReportErrorFlagsAndNumber(maybecx, JSREPORT_ERROR, js_GetErrorMessage,
nullptr, JSMSG_BAD_SURROGATE_CHAR, buffer);
@ -90,9 +94,29 @@ GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars,
return (size_t) -1;
}
template size_t
GetDeflatedUTF8StringLength(JSContext *maybecx, const Latin1Char *chars,
size_t nchars);
template size_t
GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars,
size_t nchars);
static size_t
GetDeflatedUTF8StringLength(JSContext *maybecx, JSLinearString *str)
{
size_t length = str->length();
JS::AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? GetDeflatedUTF8StringLength(maybecx, str->latin1Chars(nogc), length)
: GetDeflatedUTF8StringLength(maybecx, str->twoByteChars(nogc), length);
}
template <typename CharT>
bool
DeflateStringToUTF8Buffer(JSContext *maybecx, const jschar *src, size_t srclen,
char *dst, size_t *dstlenp)
DeflateStringToUTF8Buffer(JSContext *maybecx, const CharT *src, size_t srclen,
char *dst, size_t *dstlenp)
{
size_t i, utf8Len;
jschar c, c2;
@ -147,12 +171,33 @@ badSurrogate:
bufferTooSmall:
*dstlenp = (origDstlen - dstlen);
if (maybecx) {
js::gc::AutoSuppressGC suppress(maybecx);
JS_ReportErrorNumber(maybecx, js_GetErrorMessage, nullptr,
JSMSG_BUFFER_TOO_SMALL);
}
return false;
}
template bool
DeflateStringToUTF8Buffer(JSContext *maybecx, const Latin1Char *src, size_t srclen,
char *dst, size_t *dstlenp);
template bool
DeflateStringToUTF8Buffer(JSContext *maybecx, const jschar *src, size_t srclen,
char *dst, size_t *dstlenp);
static bool
DeflateStringToUTF8Buffer(JSContext *maybecx, JSLinearString *str, char *dst,
size_t *dstlenp)
{
size_t length = str->length();
JS::AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? DeflateStringToUTF8Buffer(maybecx, str->latin1Chars(nogc), length, dst, dstlenp)
: DeflateStringToUTF8Buffer(maybecx, str->twoByteChars(nogc), length, dst, dstlenp);
}
/*******************************************************************************
** JSAPI function prototypes
*******************************************************************************/
@ -1742,17 +1787,13 @@ jsvalToFloat(JSContext *cx, jsval val, FloatType* result)
return false;
}
template<class IntegerType>
template <class IntegerType, class CharT>
static bool
StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
StringToInteger(JSContext* cx, CharT* cp, size_t length, IntegerType* result)
{
JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
const jschar* cp = string->getChars(nullptr);
if (!cp)
return false;
const jschar* end = cp + string->length();
const CharT* end = cp + length;
if (cp == end)
return false;
@ -1796,6 +1837,21 @@ StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
return true;
}
template<class IntegerType>
static bool
StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
{
JSLinearString *linear = string->ensureLinear(cx);
if (!linear)
return false;
AutoCheckCannotGC nogc;
size_t length = linear->length();
return string->hasLatin1Chars()
? StringToInteger<IntegerType>(cx, linear->latin1Chars(nogc), length, result)
: StringToInteger<IntegerType>(cx, linear->twoByteChars(nogc), length, result);
}
// Implicitly convert val to IntegerType, allowing int, double,
// Int64, UInt64, and optionally a decimal or hexadecimal string argument.
// (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
@ -2300,10 +2356,10 @@ ImplicitConvert(JSContext* cx,
JSString* str = val.toString(); \
if (str->length() != 1) \
return TypeError(cx, #name, val); \
const jschar *chars = str->getChars(cx); \
if (!chars) \
JSLinearString *linear = str->ensureLinear(cx); \
if (!linear) \
return false; \
result = chars[0]; \
result = linear->latin1OrTwoByteChar(0); \
} else if (!jsvalToInteger(cx, val, &result)) { \
return TypeError(cx, #name, val); \
} \
@ -2346,8 +2402,8 @@ ImplicitConvert(JSContext* cx,
// TODO: Extend this so we can safely convert strings at other times also.
JSString* sourceString = val.toString();
size_t sourceLength = sourceString->length();
const jschar* sourceChars = sourceString->getChars(cx);
if (!sourceChars)
JSLinearString* sourceLinear = sourceString->ensureLinear(cx);
if (!sourceLinear)
return false;
switch (CType::GetTypeCode(baseType)) {
@ -2355,8 +2411,7 @@ ImplicitConvert(JSContext* cx,
case TYPE_signed_char:
case TYPE_unsigned_char: {
// Convert from UTF-16 to UTF-8.
size_t nbytes =
GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
size_t nbytes = GetDeflatedUTF8StringLength(cx, sourceLinear);
if (nbytes == (size_t) -1)
return false;
@ -2367,8 +2422,7 @@ ImplicitConvert(JSContext* cx,
return false;
}
ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength,
*charBuffer, &nbytes));
ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceLinear, *charBuffer, &nbytes));
(*charBuffer)[nbytes] = 0;
*freePointer = true;
break;
@ -2385,7 +2439,13 @@ ImplicitConvert(JSContext* cx,
}
*freePointer = true;
memcpy(*jscharBuffer, sourceChars, sourceLength * sizeof(jschar));
if (sourceLinear->hasLatin1Chars()) {
AutoCheckCannotGC nogc;
CopyAndInflateChars(*jscharBuffer, sourceLinear->latin1Chars(nogc), sourceLength);
} else {
AutoCheckCannotGC nogc;
mozilla::PodCopy(*jscharBuffer, sourceLinear->twoByteChars(nogc), sourceLength);
}
(*jscharBuffer)[sourceLength] = 0;
break;
}
@ -2422,17 +2482,17 @@ ImplicitConvert(JSContext* cx,
if (val.isString()) {
JSString* sourceString = val.toString();
size_t sourceLength = sourceString->length();
const jschar* sourceChars = sourceString->getChars(cx);
if (!sourceChars)
JSLinearString* sourceLinear = sourceString->ensureLinear(cx);
if (!sourceLinear)
return false;
switch (CType::GetTypeCode(baseType)) {
case TYPE_char:
case TYPE_signed_char:
case TYPE_unsigned_char: {
// Convert from UTF-16 to UTF-8.
// Convert from UTF-16 or Latin1 to UTF-8.
size_t nbytes =
GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
GetDeflatedUTF8StringLength(cx, sourceLinear);
if (nbytes == (size_t) -1)
return false;
@ -2442,8 +2502,8 @@ ImplicitConvert(JSContext* cx,
}
char* charBuffer = static_cast<char*>(buffer);
ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceChars, sourceLength,
charBuffer, &nbytes));
ASSERT_OK(DeflateStringToUTF8Buffer(cx, sourceLinear, charBuffer,
&nbytes));
if (targetLength > nbytes)
charBuffer[nbytes] = 0;
@ -2458,9 +2518,17 @@ ImplicitConvert(JSContext* cx,
return false;
}
memcpy(buffer, sourceChars, sourceLength * sizeof(jschar));
jschar *dest = static_cast<jschar*>(buffer);
if (sourceLinear->hasLatin1Chars()) {
AutoCheckCannotGC nogc;
CopyAndInflateChars(dest, sourceLinear->latin1Chars(nogc), sourceLength);
} else {
AutoCheckCannotGC nogc;
mozilla::PodCopy(dest, sourceLinear->twoByteChars(nogc), sourceLength);
}
if (targetLength > sourceLength)
static_cast<jschar*>(buffer)[sourceLength] = 0;
dest[sourceLength] = 0;
break;
}
@ -4290,8 +4358,8 @@ ArrayType::ConstructData(JSContext* cx,
// including space for the terminator.
JSString* sourceString = args[0].toString();
size_t sourceLength = sourceString->length();
const jschar* sourceChars = sourceString->getChars(cx);
if (!sourceChars)
JSLinearString* sourceLinear = sourceString->ensureLinear(cx);
if (!sourceLinear)
return false;
switch (CType::GetTypeCode(baseType)) {
@ -4299,7 +4367,7 @@ ArrayType::ConstructData(JSContext* cx,
case TYPE_signed_char:
case TYPE_unsigned_char: {
// Determine the UTF-8 length.
length = GetDeflatedUTF8StringLength(cx, sourceChars, sourceLength);
length = GetDeflatedUTF8StringLength(cx, sourceLinear);
if (length == (size_t) -1)
return false;
@ -4816,8 +4884,12 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb
}
// Add the field to the StructType's 'prototype' property.
AutoStableStringChars nameChars(cx);
if (!nameChars.initTwoByte(cx, name))
return false;
if (!JS_DefineUCProperty(cx, prototype,
name->chars(), name->length(), UndefinedHandleValue,
nameChars.twoByteChars(), name->length(), UndefinedHandleValue,
JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT,
StructType::FieldGetter, StructType::FieldSetter))
return false;
@ -5392,13 +5464,13 @@ IsEllipsis(JSContext* cx, jsval v, bool* isEllipsis)
JSString* str = v.toString();
if (str->length() != 3)
return true;
const jschar* chars = str->getChars(cx);
if (!chars)
JSLinearString *linear = str->ensureLinear(cx);
if (!linear)
return false;
jschar dot = '.';
*isEllipsis = (chars[0] == dot &&
chars[1] == dot &&
chars[2] == dot);
*isEllipsis = (linear->latin1OrTwoByteChar(0) == dot &&
linear->latin1OrTwoByteChar(1) == dot &&
linear->latin1OrTwoByteChar(2) == dot);
return true;
}

View File

@ -95,10 +95,14 @@ void
AppendString(Vector<jschar, N, AP> &v, JSString* str)
{
JS_ASSERT(str);
const jschar *chars = str->getChars(nullptr);
if (!chars)
JSLinearString *linear = str->ensureLinear(nullptr);
if (!linear)
return;
v.append(chars, str->length());
JS::AutoCheckCannotGC nogc;
if (linear->hasLatin1Chars())
v.append(linear->latin1Chars(nogc), linear->length());
else
v.append(linear->twoByteChars(nogc), linear->length());
}
template <size_t N, class AP>
@ -111,12 +115,20 @@ AppendString(Vector<char, N, AP> &v, JSString* str)
if (!v.resize(vlen + alen))
return;
const jschar *chars = str->getChars(nullptr);
if (!chars)
JSLinearString *linear = str->ensureLinear(nullptr);
if (!linear)
return;
for (size_t i = 0; i < alen; ++i)
v[i + vlen] = char(chars[i]);
JS::AutoCheckCannotGC nogc;
if (linear->hasLatin1Chars()) {
const Latin1Char *chars = linear->latin1Chars(nogc);
for (size_t i = 0; i < alen; ++i)
v[i + vlen] = char(chars[i]);
} else {
const jschar *chars = linear->twoByteChars(nogc);
for (size_t i = 0; i < alen; ++i)
v[i + vlen] = char(chars[i]);
}
}
template <class T, size_t N, class AP, size_t ArrayLength>
@ -147,23 +159,32 @@ PrependString(Vector<jschar, N, AP> &v, JSString* str)
if (!v.resize(vlen + alen))
return;
const jschar *chars = str->getChars(nullptr);
if (!chars)
JSLinearString* linear = str->ensureLinear(nullptr);
if (!linear)
return;
// Move vector data forward. This is safe since we've already resized.
memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar));
// Copy data to insert.
memcpy(v.begin(), chars, alen * sizeof(jschar));
JS::AutoCheckCannotGC nogc;
if (linear->hasLatin1Chars()) {
const Latin1Char *chars = linear->latin1Chars(nogc);
for (size_t i = 0; i < alen; i++)
v[i] = chars[i];
} else {
memcpy(v.begin(), linear->twoByteChars(nogc), alen * sizeof(jschar));
}
}
template <typename CharT>
extern size_t
GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars,
GetDeflatedUTF8StringLength(JSContext *maybecx, const CharT *chars,
size_t charsLength);
template <typename CharT>
bool
DeflateStringToUTF8Buffer(JSContext *maybecx, const jschar *src, size_t srclen,
DeflateStringToUTF8Buffer(JSContext *maybecx, const CharT *src, size_t srclen,
char *dst, size_t *dstlenp);
@ -234,15 +255,21 @@ struct FieldHashPolicy : DefaultHasher<JSFlatString*>
typedef JSFlatString* Key;
typedef Key Lookup;
static uint32_t hash(const Lookup &l) {
const jschar* s = l->chars();
size_t n = l->length();
template <typename CharT>
static uint32_t hash(const CharT *s, size_t n) {
uint32_t hash = 0;
for (; n > 0; s++, n--)
hash = hash * 33 + *s;
return hash;
}
static uint32_t hash(const Lookup &l) {
JS::AutoCheckCannotGC nogc;
return l->hasLatin1Chars()
? hash(l->latin1Chars(nogc), l->length())
: hash(l->twoByteChars(nogc), l->length());
}
static bool match(const Key &k, const Lookup &l) {
if (k == l)
return true;
@ -250,7 +277,7 @@ struct FieldHashPolicy : DefaultHasher<JSFlatString*>
if (k->length() != l->length())
return false;
return memcmp(k->chars(), l->chars(), k->length() * sizeof(jschar)) == 0;
return EqualChars(k, l);
}
};

View File

@ -104,13 +104,13 @@ Library::Create(JSContext* cx, jsval path_, JSCTypesCallbacks* callbacks)
RootedFlatString pathStr(cx, JS_FlattenString(cx, path.toString()));
if (!pathStr)
return nullptr;
AutoStableStringChars pathStrChars(cx);
if (!pathStrChars.initTwoByte(cx, pathStr))
return nullptr;
#ifdef XP_WIN
// On Windows, converting to native charset may corrupt path string.
// So, we have to use Unicode path directly.
char16ptr_t pathChars = JS_GetFlatStringChars(pathStr);
if (!pathChars)
return nullptr;
char16ptr_t pathChars = pathStrChars.twoByteChars();
libSpec.value.pathname_u = pathChars;
libSpec.type = PR_LibSpec_PathnameU;
#else
@ -119,7 +119,7 @@ Library::Create(JSContext* cx, jsval path_, JSCTypesCallbacks* callbacks)
char* pathBytes;
if (callbacks && callbacks->unicodeToNative) {
pathBytes =
callbacks->unicodeToNative(cx, pathStr->chars(), pathStr->length());
callbacks->unicodeToNative(cx, pathStrChars.twoByteChars(), pathStr->length());
if (!pathBytes)
return nullptr;
@ -127,7 +127,7 @@ Library::Create(JSContext* cx, jsval path_, JSCTypesCallbacks* callbacks)
// Fallback: assume the platform native charset is UTF-8. This is true
// for Mac OS X, Android, and probably Linux.
size_t nbytes =
GetDeflatedUTF8StringLength(cx, pathStr->chars(), pathStr->length());
GetDeflatedUTF8StringLength(cx, pathStrChars.twoByteChars(), pathStr->length());
if (nbytes == (size_t) -1)
return nullptr;
@ -135,7 +135,7 @@ Library::Create(JSContext* cx, jsval path_, JSCTypesCallbacks* callbacks)
if (!pathBytes)
return nullptr;
ASSERT_OK(DeflateStringToUTF8Buffer(cx, pathStr->chars(),
ASSERT_OK(DeflateStringToUTF8Buffer(cx, pathStrChars.twoByteChars(),
pathStr->length(), pathBytes, &nbytes));
pathBytes[nbytes] = 0;
}

View File

@ -0,0 +1,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
gcstats: gcstats.cpp ../../gc/GCTraceFormat.h Makefile
$(CXX) -std=c++11 -g -O2 -I../.. -o $@ $<

View File

@ -0,0 +1,765 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Read and process GC trace logs.
*/
#include "gc/GCTraceFormat.h"
#define __STDC_FORMAT_MACROS
#include <assert.h>
#include <inttypes.h>
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <functional>
#include <unordered_map>
#include <vector>
// State of the program
enum Heap
{
Nursery,
TenuredHeap,
HeapKinds
};
enum State
{
StateMutator,
StateMinorGC,
StateMajorGC
};
typedef uint64_t address;
typedef uint8_t AllocKind;
typedef uint8_t ClassId;
struct AllocInfo
{
const uint64_t serial;
const AllocKind kind;
const Heap initialHeap;
ClassId classId;
AllocInfo(uint64_t allocCount, uint8_t kind, Heap loc)
: serial(allocCount), kind(kind), initialHeap(loc), classId(0)
{
assert(kind < AllocKinds);
assert(initialHeap < HeapKinds);
}
};
struct ClassInfo
{
const ClassId id;
const char *name;
const uint32_t flags;
ClassInfo(ClassId id, const char *name, uint32_t flags)
: id(id), name(name), flags(flags) {}
};
typedef std::unordered_map<address, AllocInfo> AllocMap;
typedef std::unordered_map<address, ClassId> ClassMap;
typedef std::vector<ClassInfo> ClassVector;
uint64_t thingSizes[AllocKinds];
AllocMap nurseryThings;
AllocMap tenuredThings;
ClassMap classMap;
ClassVector classes;
uint64_t allocCount = 0;
// Collected data
const unsigned MaxClasses = 128;
const unsigned LifetimeBinLog = 10;
const unsigned MaxLifetimeBins = 40;
const unsigned AugHeapKinds = HeapKinds + 1;
const unsigned HeapTotal = HeapKinds;
const unsigned AugAllocKinds = AllocKinds + 1;
const unsigned AllocKindTotal = AllocKinds;
const unsigned AugLifetimeBins = MaxLifetimeBins + 1;
const unsigned LifetimeBinTotal = MaxLifetimeBins;
const unsigned AugClasses = MaxClasses + 1;
const unsigned ClassTotal = MaxClasses;
struct CountByHeap
{
CountByHeap() { memset(this, 0, sizeof(*this)); }
void inc(Heap heap) {
assert(heap < AugHeapKinds);
++count[heap];
++count[HeapTotal];
}
uint64_t get(unsigned heap) {
assert(heap < AugHeapKinds);
return count[heap];
}
private:
uint64_t count[AugHeapKinds];
};
struct CountByHeapAndKind
{
CountByHeapAndKind() {}
void inc(Heap heap, AllocKind kind) {
assert(kind < AugAllocKinds);
count[kind].inc(heap);
count[AllocKindTotal].inc(heap);
}
uint64_t get(unsigned heap, unsigned kind) {
assert(kind < AugAllocKinds);
return count[kind].get(heap);
}
private:
CountByHeap count[AugAllocKinds];
};
struct CountByHeapKindAndLifetime
{
CountByHeapKindAndLifetime() {}
void inc(Heap heap, AllocKind kind, unsigned lifetimeBin) {
assert(lifetimeBin < MaxLifetimeBins);
count[lifetimeBin].inc(heap, kind);
count[LifetimeBinTotal].inc(heap, kind);
}
uint64_t get(unsigned heap, unsigned kind, unsigned lifetimeBin) {
assert(lifetimeBin < AugLifetimeBins);
return count[lifetimeBin].get(heap, kind);
}
private:
CountByHeapAndKind count[AugLifetimeBins];
};
struct CountByHeapAndClass
{
CountByHeapAndClass() {}
void inc(Heap heap, unsigned classId) {
assert(classId < MaxClasses);
count[classId].inc(heap);
count[ClassTotal].inc(heap);
}
uint64_t get(unsigned heap, unsigned classId) {
assert(classId < AugClasses);
return count[classId].get(heap);
}
private:
CountByHeap count[AugClasses];
};
struct CountByHeapClassAndLifetime
{
CountByHeapClassAndLifetime() {}
void inc(Heap heap, unsigned classId, unsigned lifetimeBin) {
assert(lifetimeBin < MaxLifetimeBins);
count[lifetimeBin].inc(heap, classId);
count[LifetimeBinTotal].inc(heap, classId);
}
uint64_t get(unsigned heap, unsigned classId, unsigned lifetimeBin) {
assert(lifetimeBin < AugLifetimeBins);
return count[lifetimeBin].get(heap, classId);
}
private:
CountByHeapAndClass count[AugLifetimeBins];
};
unsigned timesliceSize;
unsigned lifetimeBins;
CountByHeapKindAndLifetime allocTotals;
std::vector<CountByHeapKindAndLifetime> allocTotalsBySlice;
CountByHeapClassAndLifetime objectTotals;
std::vector<uint64_t> gcBytesAllocatedInSlice;
std::vector<uint64_t> gcBytesFreedInSlice;
static void
die(const char *format, ...)
{
va_list va;
va_start(va, format);
vfprintf(stderr, format, va);
fprintf(stderr, "\n");
va_end(va);
exit(1);
}
const uint64_t FirstBinSize = 100;
const unsigned BinLog = 2;
static unsigned
getBin(uint64_t lifetime)
{
/*
* Calculate a bin number for a given lifetime.
*
* We use a logarithmic scale, starting with a bin size of 100 and doubling
* from there.
*/
static double logDivisor = log(BinLog);
if (lifetime < FirstBinSize)
return 0;
return unsigned(log(lifetime / FirstBinSize) / logDivisor) + 1;
}
static unsigned
binLimit(unsigned bin)
{
return unsigned(pow(BinLog, bin) * FirstBinSize);
}
static void
testBinning()
{
assert(getBin(0) == 0);
assert(getBin(FirstBinSize - 1) == 0);
assert(getBin(FirstBinSize) == 1);
assert(getBin(2 * FirstBinSize - 1) == 1);
assert(getBin(2 * FirstBinSize) == 2);
assert(getBin(4 * FirstBinSize - 1) == 2);
assert(getBin(4 * FirstBinSize) == 3);
assert(binLimit(0) == FirstBinSize);
assert(binLimit(1) == 2 * FirstBinSize);
assert(binLimit(2) == 4 * FirstBinSize);
assert(binLimit(3) == 8 * FirstBinSize);
}
static const char *
allocKindName(AllocKind kind)
{
static const char *AllocKindNames[] = {
"Object0",
"Object0Bg",
"Object2",
"Object2Bg",
"Object4",
"Object4Bg",
"Object8",
"Object8Bg",
"Object12",
"Object12Bg",
"Object16",
"Object16Bg",
"Script",
"LazyScript",
"Shape",
"BaseShape",
"TypeObject",
"FatInlineString",
"String",
"ExternalString",
"Symbol",
"JitCode",
"Total"
};
assert(sizeof(AllocKindNames) / sizeof(const char *) == AugAllocKinds);
assert(kind < AugAllocKinds);
return AllocKindNames[kind];
}
static const char *
heapName(unsigned heap)
{
static const char *HeapNames[] = {
"nursery",
"tenured heap",
"all"
};
assert(heap < AugHeapKinds);
return HeapNames[heap];
}
static const char *
heapLabel(unsigned heap)
{
static const char *HeapLabels[] = {
"Nursery",
"Tenured heap",
"Total"
};
assert(heap < AugHeapKinds);
return HeapLabels[heap];
}
static void
outputGcBytesAllocated(FILE *file)
{
fprintf(file, "# Total GC bytes allocated by timeslice\n");
fprintf(file, "# Total allocations: %" PRIu64 "\n", allocCount);
fprintf(file, "Time, GCBytesAllocated\n");
uint64_t timesliceCount = allocCount / timesliceSize + 1;
uint64_t total = 0;
for (uint64_t i = 0; i < timesliceCount; ++i) {
total += gcBytesAllocatedInSlice[i];
fprintf(file, "%12" PRIu64 ", %12" PRIu64 "\n", i * timesliceSize, total);
}
}
static void
outputGcBytesUsed(FILE *file)
{
fprintf(file, "# Total GC bytes used by timeslice\n");
fprintf(file, "# Total allocations: %" PRIu64 "\n", allocCount);
fprintf(file, "Time, GCBytesUsed\n");
uint64_t timesliceCount = allocCount / timesliceSize + 1;
uint64_t total = 0;
for (uint64_t i = 0; i < timesliceCount; ++i) {
total += gcBytesAllocatedInSlice[i] - gcBytesFreedInSlice[i];
fprintf(file, "%12" PRIu64 ", %12" PRIu64 "\n", i * timesliceSize, total);
}
}
static void
outputThingCounts(FILE *file)
{
fprintf(file, "# GC thing allocation count in nursery and tenured heap by kind\n");
fprintf(file, "# This shows what kind of things we are allocating in the nursery\n");
fprintf(file, "# Total allocations: %" PRIu64 "\n", allocCount);
fprintf(file, "Kind, Nursery, Tenured heap\n");
for (unsigned i = 0; i < AllocKinds; ++i) {
fprintf(file, "%15s, %8" PRIu64 ", %8" PRIu64 "\n", allocKindName(i),
allocTotals.get(Nursery, i, LifetimeBinTotal),
allocTotals.get(TenuredHeap, i, LifetimeBinTotal));
}
}
static void
outputObjectCounts(FILE *file)
{
fprintf(file, "# Object allocation count in nursery and tenured heap by class\n");
fprintf(file, "# This shows what kind of objects we are allocating in the nursery\n");
fprintf(file, "# Total allocations: %" PRIu64 "\n", allocCount);
fprintf(file, "Class, Nursery, Tenured heap, Total\n");
for (unsigned i = 0; i < classes.size(); ++i) {
fprintf(file, "%30s, %8" PRIu64 ", %8" PRIu64 ", %8" PRIu64 "\n",
classes[i].name,
objectTotals.get(Nursery, i, LifetimeBinTotal),
objectTotals.get(TenuredHeap, i, LifetimeBinTotal),
objectTotals.get(HeapTotal, i, LifetimeBinTotal));
}
}
static void
outputLifetimeByHeap(FILE *file)
{
fprintf(file, "# Lifetime of all things (in log2 bins) by initial heap\n");
fprintf(file, "# NB invalid unless execution was traced with appropriate zeal\n");
fprintf(file, "# Total allocations: %" PRIu64 "\n", allocCount);
fprintf(file, "Lifetime");
for (unsigned i = 0; i < HeapKinds; ++i)
fprintf(file, ", %s", heapLabel(i));
fprintf(file, "\n");
for (unsigned i = 0; i < lifetimeBins; ++i) {
fprintf(file, "%8d", binLimit(i));
for (unsigned j = 0; j < HeapKinds; ++j)
fprintf(file, ", %8" PRIu64, allocTotals.get(j, AllocKindTotal, i));
fprintf(file, "\n");
}
}
static void
outputLifetimeByKind(FILE *file, unsigned initialHeap)
{
assert(initialHeap < AugHeapKinds);
fprintf(file, "# Lifetime of %s things (in log2 bins) by kind\n", heapName(initialHeap));
fprintf(file, "# NB invalid unless execution was traced with appropriate zeal\n");
fprintf(file, "# Total allocations: %" PRIu64 "\n", allocCount);
fprintf(file, "Lifetime");
for (unsigned i = 0; i < AllocKinds; ++i)
fprintf(file, ", %15s", allocKindName(i));
fprintf(file, "\n");
for (unsigned i = 0; i < lifetimeBins; ++i) {
fprintf(file, "%8d", binLimit(i));
for (unsigned j = 0; j < AllocKinds; ++j)
fprintf(file, ", %8" PRIu64, allocTotals.get(initialHeap, j, i));
fprintf(file, "\n");
}
}
static void
outputLifetimeByClass(FILE *file, unsigned initialHeap)
{
assert(initialHeap < AugHeapKinds);
fprintf(file, "# Lifetime of %s things (in log2 bins) by class\n", heapName(initialHeap));
fprintf(file, "# NB invalid unless execution was traced with appropriate zeal\n");
fprintf(file, "# Total allocations: %" PRIu64 "\n", allocCount);
fprintf(file, "Lifetime");
for (unsigned i = 0; i < classes.size(); ++i)
fprintf(file, ", %15s", classes[i].name);
fprintf(file, "\n");
for (unsigned i = 0; i < lifetimeBins; ++i) {
fprintf(file, "%8d", binLimit(i));
for (unsigned j = 0; j < classes.size(); ++j)
fprintf(file, ", %8" PRIu64, objectTotals.get(initialHeap, j, i));
fprintf(file, "\n");
}
}
static void
outputLifetimeBySlice(FILE *file)
{
fprintf(file, "# Lifetime (in log2 bins) by allocation timeslice for all things\n");
fprintf(file, "Timeslice");
for (unsigned i = 0; i < lifetimeBins; ++i)
fprintf(file, ", Lifetime<%d", binLimit(i));
fprintf(file, "\n");
uint64_t timesliceCount = allocCount / timesliceSize + 1;
for (uint64_t i = 0; i < timesliceCount; ++i) {
fprintf(file, "%8" PRIu64, i);
for (unsigned j = 0; j < lifetimeBins; ++j) {
fprintf(file, ", %8" PRIu64,
allocTotalsBySlice[i].get(HeapTotal, AllocKindTotal, j));
}
fprintf(file, "\n");
}
}
static void
processAlloc(const AllocInfo &info, uint64_t finalizeTime)
{
uint64_t lifetime = finalizeTime - info.serial;
unsigned timeslice = info.serial / timesliceSize;
unsigned lifetimeBin = getBin(lifetime);
assert(lifetimeBin < lifetimeBins);
allocTotals.inc(info.initialHeap, info.kind, lifetimeBin);
allocTotalsBySlice[timeslice].inc(info.initialHeap, info.kind, lifetimeBin);
if (info.kind <= LastObjectAllocKind)
objectTotals.inc(info.initialHeap, info.classId, lifetimeBin);
uint64_t size = thingSizes[info.kind];
gcBytesAllocatedInSlice[timeslice] += size;
gcBytesFreedInSlice[finalizeTime / timesliceSize] += size;
}
static bool
readTrace(FILE* file, uint64_t& trace)
{
if (fread(&trace, sizeof(trace), 1, file) != 1) {
if (feof(file))
return false;
else
die("Error reading input");
}
return true;
}
static GCTraceEvent
getTraceEvent(uint64_t trace)
{
uint64_t event = trace >> TraceEventShift;
assert(event < GCTraceEventCount);
return (GCTraceEvent)event;
}
static uint64_t
getTracePayload(uint64_t trace)
{
return trace & ((1lu << TracePayloadBits) - 1);
}
static uint8_t
getTraceExtra(uint64_t trace)
{
uint64_t extra = (trace >> TraceExtraShift) & ((1 << TraceExtraBits) - 1);
assert(extra < 256);
return (uint8_t)extra;
}
static uint64_t
expectTrace(FILE *file, GCTraceEvent event)
{
uint64_t trace;
if (!readTrace(file, trace))
die("End of file while expecting trace %d", event);
if (getTraceEvent(trace) != event)
die("Expected trace %d but got trace %d", event, getTraceEvent(trace));
return getTracePayload(trace);
}
static uint64_t
expectDataAddress(FILE *file)
{
return expectTrace(file, TraceDataAddress);
}
static uint32_t
expectDataInt(FILE *file)
{
return (uint32_t)expectTrace(file, TraceDataInt);
}
static char *
expectDataString(FILE *file)
{
uint64_t length = expectTrace(file, TraceDataString);
assert(length < 256); // Sanity check
char *string = static_cast<char *>(malloc(length + 1));
if (!string)
die("Out of memory while reading string data");
const unsigned charsPerWord = sizeof(uint64_t);
unsigned wordCount = (length + charsPerWord - 1) / charsPerWord;
for (unsigned i = 0; i < wordCount; ++i) {
if (fread(&string[i * charsPerWord], sizeof(char), charsPerWord, file) != charsPerWord)
die("Error or EOF while reading string data");
}
string[length] = 0;
return string;
}
static void
createClassInfo(const char *name, uint32_t flags, address clasp = 0)
{
ClassId id = classes.size();
classes.push_back(ClassInfo(id, name, flags));
if (clasp)
classMap.emplace(clasp, id);
}
static void
readClassInfo(FILE *file, address clasp)
{
assert(clasp);
uint32_t flags = expectDataInt(file);
char *name = expectDataString(file);
createClassInfo(name, flags, clasp);
}
static void
allocHeapThing(address thing, AllocKind kind)
{
uint64_t allocTime = allocCount++;
tenuredThings.emplace(thing, AllocInfo(allocTime, kind, TenuredHeap));
}
static void
allocNurseryThing(address thing, AllocKind kind)
{
uint64_t allocTime = allocCount++;
nurseryThings.emplace(thing, AllocInfo(allocTime, kind, Nursery));
}
static void
setObjectClass(address obj, address clasp)
{
auto i = classMap.find(clasp);
assert(i != classMap.end());
ClassId id = i->second;
assert(id < classes.size());
auto j = nurseryThings.find(obj);
if (j == nurseryThings.end()) {
j = tenuredThings.find(obj);
if (j == tenuredThings.end())
die("Can't find allocation for object %p", obj);
}
j->second.classId = id;
}
static void
promoteToTenured(address src, address dst)
{
auto i = nurseryThings.find(src);
assert(i != nurseryThings.end());
AllocInfo alloc = i->second;
tenuredThings.emplace(dst, alloc);
nurseryThings.erase(i);
}
static void
finalizeThing(const AllocInfo &info)
{
processAlloc(info, allocCount);
}
static void
sweepNursery()
{
for (auto i = nurseryThings.begin(); i != nurseryThings.end(); ++i) {
finalizeThing(i->second);
}
nurseryThings.clear();
}
static void
finalizeTenuredThing(address thing)
{
auto i = tenuredThings.find(thing);
assert(i != tenuredThings.end());
finalizeThing(i->second);
tenuredThings.erase(i);
}
static void
updateTimeslices(std::vector<uint64_t> &data, uint64_t lastTime, uint64_t currentTime, uint64_t value)
{
unsigned firstSlice = (lastTime / timesliceSize) + 1;
unsigned lastSlice = currentTime / timesliceSize;
for (unsigned i = firstSlice; i <= lastSlice; ++i)
data[i] = value;
}
static void
processTraceFile(const char *filename)
{
FILE *file;
file = fopen(filename, "r");
if (!file)
die("Can't read file: %s", filename);
// Get a conservative estimate of the total number of allocations so we can
// allocate buffers in advance.
fseek(file, 0, SEEK_END);
size_t length = ftell(file);
fseek(file, 0, SEEK_SET);
size_t maxTraces = length / sizeof(uint64_t);
uint64_t trace;
if (!readTrace(file, trace))
die("Empty input file");
if (getTraceEvent(trace) != TraceEventInit)
die("Can't parse input file");
if (getTraceExtra(trace) != TraceFormatVersion)
die("Unexpected format version %d", getTraceExtra(trace));
for (unsigned kind = 0; kind < AllocKinds; ++kind)
thingSizes[kind] = expectTrace(file, TraceEventThingSize);
timesliceSize = 1000;
while ((maxTraces / timesliceSize ) > 1000)
timesliceSize *= 2;
size_t maxTimeslices = maxTraces / timesliceSize;
allocTotalsBySlice.reserve(maxTimeslices);
gcBytesAllocatedInSlice.reserve(maxTimeslices);
gcBytesFreedInSlice.reserve(maxTimeslices);
lifetimeBins = getBin(maxTraces) + 1;
assert(lifetimeBins <= MaxLifetimeBins);
createClassInfo("unknown", 0);
State state = StateMutator;
while (readTrace(file, trace)) {
GCTraceEvent event = getTraceEvent(trace);
switch (event) {
case TraceEventNurseryAlloc:
assert(state == StateMutator);
allocNurseryThing(getTracePayload(trace), getTraceExtra(trace));
break;
case TraceEventTenuredAlloc:
assert(state == StateMutator);
allocHeapThing(getTracePayload(trace), getTraceExtra(trace));
break;
case TraceEventClassInfo:
assert(state == StateMutator);
readClassInfo(file, getTracePayload(trace));
break;
case TraceEventCreateObject:
assert(state == StateMutator);
setObjectClass(getTracePayload(trace), expectDataAddress(file));
break;
case TraceEventMinorGCStart:
assert(state == StateMutator);
state = StateMinorGC;
break;
case TraceEventPromoteToTenured:
assert(state == StateMinorGC);
promoteToTenured(getTracePayload(trace), expectDataAddress(file));
break;
case TraceEventMinorGCEnd:
assert(state == StateMinorGC);
sweepNursery();
state = StateMutator;
break;
case TraceEventMajorGCStart:
assert(state == StateMutator);
state = StateMajorGC;
break;
case TraceEventTenuredFinalize:
assert(state == StateMajorGC);
finalizeTenuredThing(getTracePayload(trace));
break;
case TraceEventMajorGCEnd:
assert(state == StateMajorGC);
state = StateMutator;
break;
default:
assert(false);
die("Unexpected trace event %d", event);
break;
}
}
// Correct number of lifetime bins now we know the real allocation count.
assert(allocCount < maxTraces);
lifetimeBins = getBin(allocCount) + 1;
assert(lifetimeBins <= MaxLifetimeBins);
fclose(file);
}
template <class func>
void withOutputFile(const char *base, const char *name, func f)
{
const size_t bufSize = 256;
char filename[bufSize];
int r = snprintf(filename, bufSize, "%s%s", base, name);
assert(r > 0 && r < bufSize);
FILE *file = fopen(filename, "w");
if (!file)
die("Can't write to %s", filename);
f(file);
fclose(file);
}
int
main(int argc, const char *argv[])
{
testBinning();
if (argc != 3)
die("usage: gctrace INPUT_FILE OUTPUT_BASE");
const char* inputFile = argv[1];
const char* outputBase = argv[2];
processTraceFile(inputFile);
using namespace std::placeholders;
withOutputFile(outputBase, "-bytesAllocatedBySlice.csv", outputGcBytesAllocated);
withOutputFile(outputBase, "-bytesUsedBySlice.csv", outputGcBytesUsed);
withOutputFile(outputBase, "-thingCounts.csv", outputThingCounts);
withOutputFile(outputBase, "-objectCounts.csv", outputObjectCounts);
withOutputFile(outputBase, "-lifetimeByClassForNursery.csv",
std::bind(outputLifetimeByClass, _1, Nursery));
withOutputFile(outputBase, "-lifetimeByKindForHeap.csv",
std::bind(outputLifetimeByKind, _1, TenuredHeap));
withOutputFile(outputBase, "-lifetimeByHeap.csv", outputLifetimeByHeap);
withOutputFile(outputBase, "-lifetimeBySlice.csv", outputLifetimeBySlice);
return 0;
}

View File

@ -85,39 +85,70 @@ function expressionUsesVariable(exp, variable)
return false;
}
function edgeUsesVariable(edge, variable)
// Detect simple |return nullptr;| statements.
function isReturningImmobileValue(edge, variable)
{
if (variable.Kind == "Return") {
if (edge.Exp[0].Kind == "Var" && sameVariable(edge.Exp[0].Variable, variable)) {
if (edge.Exp[1].Kind == "Int" && edge.Exp[1].String == "0") {
return true;
}
}
}
return false;
}
// If the edge uses the given variable, return the earliest point at which the
// use is definite. Usually, that means the source of the edge (anything that
// reaches that source point will end up using the variable, but there may be
// other ways to reach the destination of the edge.)
//
// Return values are implicitly used at the very last point in the function.
// This makes a difference: if an RAII class GCs in its destructor, we need to
// start looking at the final point in the function, not one point back from
// that, since that would skip over the GCing call.
//
function edgeUsesVariable(edge, variable, body)
{
if (ignoreEdgeUse(edge, variable))
return false;
return 0;
if (variable.Kind == "Return" && body.Index[1] == edge.Index[1] && body.BlockId.Kind == "Function")
return edge.Index[1]; // Last point in function body uses the return value.
var src = edge.Index[0];
switch (edge.Kind) {
case "Assign":
if (isReturningImmobileValue(edge, variable))
return 0;
if (expressionUsesVariable(edge.Exp[0], variable))
return true;
return expressionUsesVariable(edge.Exp[1], variable);
return src;
return expressionUsesVariable(edge.Exp[1], variable) ? src : 0;
case "Assume":
return expressionUsesVariable(edge.Exp[0], variable);
return expressionUsesVariable(edge.Exp[0], variable) ? src : 0;
case "Call":
if (expressionUsesVariable(edge.Exp[0], variable))
return true;
return src;
if (1 in edge.Exp && expressionUsesVariable(edge.Exp[1], variable))
return true;
return src;
if ("PEdgeCallInstance" in edge) {
if (expressionUsesVariable(edge.PEdgeCallInstance.Exp, variable))
return true;
return src;
}
if ("PEdgeCallArguments" in edge) {
for (var exp of edge.PEdgeCallArguments.Exp) {
if (expressionUsesVariable(exp, variable))
return true;
return src;
}
}
return false;
return 0;
case "Loop":
return false;
return 0;
default:
assert(false);
@ -159,7 +190,7 @@ function edgeKillsVariable(edge, variable)
if (edge.Kind == "Assign") {
var lhs = edge.Exp[0];
if (lhs.Kind == "Var" && sameVariable(lhs.Variable, variable))
return true;
return !isReturningImmobileValue(edge, variable);
}
if (edge.Kind != "Call")
@ -224,7 +255,7 @@ function edgeCanGC(edge)
var variable = callee.Variable;
assert(variable.Kind == "Func");
var callee = mangled(variable.Name[0]);
if (callee in gcFunctions)
if ((callee in gcFunctions) || ((callee + internalMarker) in gcFunctions))
return "'" + variable.Name[0] + "'";
return null;
}
@ -242,11 +273,11 @@ function edgeCanGC(edge)
return indirectCallCannotGC(functionName, varName) ? null : "*" + varName;
}
function variableUseFollowsGC(suppressed, variable, worklist)
function variableUsePrecedesGC(suppressed, variable, worklist)
{
// Scan through all edges following an unrooted variable use, using an
// explicit worklist. A worklist contains a following edge together with a
// description of where one of its predecessors GC'd (if any).
// Scan through all edges preceding an unrooted variable use, using an
// explicit worklist. A worklist contains an incoming edge together with a
// description of where it or one of its successors GC'd (if any).
while (worklist.length) {
var entry = worklist.pop();
@ -281,6 +312,8 @@ function variableUseFollowsGC(suppressed, variable, worklist)
}
}
} else if (variable.Kind == "Arg" && entry.gcInfo) {
// The scope of arguments starts at the beginning of the
// function
return {gcInfo:entry.gcInfo, why:entry};
}
}
@ -294,7 +327,7 @@ function variableUseFollowsGC(suppressed, variable, worklist)
if (edgeKillsVariable(edge, variable)) {
if (entry.gcInfo)
return {gcInfo:entry.gcInfo, why:entry};
return {gcInfo: entry.gcInfo, why: {body:body, ppoint:source, gcInfo:entry.gcInfo, why:entry } }
if (!body.minimumUse || source < body.minimumUse)
body.minimumUse = source;
continue;
@ -307,7 +340,7 @@ function variableUseFollowsGC(suppressed, variable, worklist)
gcInfo = {name:gcName, body:body, ppoint:source};
}
if (edgeUsesVariable(edge, variable)) {
if (edgeUsesVariable(edge, variable, body)) {
if (gcInfo)
return {gcInfo:gcInfo, why:entry};
if (!body.minimumUse || source < body.minimumUse)
@ -350,11 +383,15 @@ function variableLiveAcrossGC(suppressed, variable)
if (!("PEdge" in body))
continue;
for (var edge of body.PEdge) {
if (edgeUsesVariable(edge, variable) && !edgeKillsVariable(edge, variable)) {
var worklist = [{body:body, ppoint:edge.Index[0], gcInfo:null, why:null}];
var call = variableUseFollowsGC(suppressed, variable, worklist);
if (call)
var usePoint = edgeUsesVariable(edge, variable, body);
if (usePoint && !edgeKillsVariable(edge, variable)) {
// Found a use, possibly after a GC.
var worklist = [{body:body, ppoint:usePoint, gcInfo:null, why:null}];
var call = variableUsePrecedesGC(suppressed, variable, worklist);
if (call) {
call.afterGCUse = usePoint;
return call;
}
}
}
}
@ -392,8 +429,7 @@ function computePrintedLines(functionName)
// Distribute lines of output to the block they originate from.
var currentBody = null;
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
for (var line of lines) {
if (/^block:/.test(line)) {
if (match = /:(loop#[\d#]+)/.exec(line)) {
var loop = match[1];
@ -436,6 +472,8 @@ function locationLine(text)
function printEntryTrace(functionName, entry)
{
var gcPoint = ('gcInfo' in entry) ? entry.gcInfo.ppoint : 0;
if (!functionBodies[0].lines)
computePrintedLines(functionName);
@ -443,17 +481,24 @@ function printEntryTrace(functionName, entry)
var ppoint = entry.ppoint;
var lineText = findLocation(entry.body, ppoint);
var edgeText = null;
var edgeText = "";
if (entry.why && entry.why.body == entry.body) {
// If the next point in the trace is in the same block, look for an edge between them.
var next = entry.why.ppoint;
for (var line of entry.body.lines) {
if (match = /\((\d+),(\d+),/.exec(line)) {
if (match[1] == ppoint && match[2] == next)
edgeText = line; // May be multiple
if (!entry.body.edgeTable) {
var table = {};
entry.body.edgeTable = table;
for (var line of entry.body.lines) {
if (match = /\((\d+),(\d+),/.exec(line))
table[match[1] + "," + match[2]] = line; // May be multiple?
}
}
edgeText = entry.body.edgeTable[ppoint + "," + next];
assert(edgeText);
if (ppoint == gcPoint)
edgeText += " [[GC call]]";
} else {
// Look for any outgoing edge from the chosen point.
for (var line of entry.body.lines) {
@ -464,9 +509,11 @@ function printEntryTrace(functionName, entry)
}
}
}
if (ppoint == entry.body.Index[1] && entry.body.BlockId.Kind == "Function")
edgeText += " [[end of function]]";
}
print(" " + lineText + (edgeText ? ": " + edgeText : ""));
print(" " + lineText + (edgeText.length ? ": " + edgeText : ""));
entry = entry.why;
}
}
@ -499,13 +546,14 @@ function processBodies(functionName)
return;
var suppressed = (mangled(functionName) in suppressedFunctions);
for (var variable of functionBodies[0].DefineVariable) {
if (variable.Variable.Kind == "Return")
continue;
var name;
if (variable.Variable.Kind == "This")
name = "this";
else if (variable.Variable.Kind == "Return")
name = "<returnvalue>";
else
name = variable.Variable.Name[0];
if (isRootedType(variable.Type)) {
if (!variableLiveAcrossGC(suppressed, variable.Variable)) {
// The earliest use of the variable should be its constructor.
@ -557,6 +605,13 @@ var each = Math.floor(N/numBatches);
var start = minStream + each * (batch - 1);
var end = Math.min(minStream + each * batch - 1, maxStream);
// For debugging: Set this variable to the function name you're interested in
// debugging and run once. That will print out the nameIndex of that function.
// Insert that into the following statement to go directly to just that
// function. Add your debugging printouts or debugger; statements or whatever.
var theFunctionNameToFind;
// var start = end = 12345;
for (var nameIndex = start; nameIndex <= end; nameIndex++) {
var name = xdb.read_key(nameIndex);
var functionName = name.readString();
@ -566,6 +621,15 @@ for (var nameIndex = start; nameIndex <= end; nameIndex++) {
xdb.free_string(data);
functionBodies = JSON.parse(json);
if (theFunctionNameToFind) {
if (functionName == theFunctionNameToFind) {
printErr("nameIndex = " + nameIndex);
quit(1);
} else {
continue;
}
}
for (var body of functionBodies)
body.suppressed = [];
for (var body of functionBodies) {

View File

@ -248,6 +248,12 @@ function isOverridableField(initialCSU, csu, field)
return false;
if (initialCSU == 'nsIXPConnectJSObjectHolder' && field == 'GetJSObject')
return false;
if (initialCSU == 'nsIXPConnect' && field == 'GetSafeJSContext')
return false;
if (initialCSU == 'nsIScriptContext') {
if (field == 'GetWindowProxy' || field == 'GetWindowProxyPreserveColor')
return false;
}
return true;
}

View File

@ -276,6 +276,22 @@ for (var nameIndex = minStream; nameIndex <= maxStream; nameIndex++) {
for (var body of functionBodies)
processBody(functionName, body);
// GCC generates multiple constructors and destructors ("in-charge" and
// "not-in-charge") to handle virtual base classes. They are normally
// identical, and it appears that GCC does some magic to alias them to the
// same thing. But this aliasing is not visible to the analysis. So we'll
// add a dummy call edge from "foo" -> "foo *INTERNAL* ", since only "foo"
// will show up as called but only "foo *INTERNAL* " will be emitted in the
// case where the constructors are identical.
//
// This is slightly conservative in the case where they are *not*
// identical, but that should be rare enough that we don't care.
var markerPos = functionName.indexOf(internalMarker);
if (markerPos > 0) {
var inChargeXTor = functionName.substr(0, markerPos) + functionName.substr(markerPos + internalMarker.length);
print("D " + memo(inChargeXTor) + " " + memo(functionName));
}
xdb.free_string(name);
xdb.free_string(data);
}

View File

@ -2,6 +2,10 @@
"use strict";
// gcc appends this to mangled function names for "not in charge"
// constructors/destructors.
var internalMarker = " *INTERNAL* ";
function assert(x, msg)
{
if (x)

View File

@ -319,8 +319,9 @@ class GCRuntime
void incrementalCollectSlice(int64_t budget, JS::gcreason::Reason reason,
JSGCInvocationKind gckind);
void pushZealSelectedObjects();
bool beginMarkPhase();
bool shouldPreserveJITCode(JSCompartment *comp, int64_t currentTime);
bool beginMarkPhase(JS::gcreason::Reason reason);
bool shouldPreserveJITCode(JSCompartment *comp, int64_t currentTime,
JS::gcreason::Reason reason);
void bufferGrayRoots();
bool drainMarkStack(SliceBudget &sliceBudget, gcstats::Phase phase);
template <class CompartmentIterT> void markWeakReferences(gcstats::Phase phase);

195
js/src/gc/GCTrace.cpp Normal file
View File

@ -0,0 +1,195 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef JS_GC_TRACE
#include "gc/GCTrace.h"
#include <stdio.h>
#include <string.h>
#include "gc/GCTraceFormat.h"
#include "js/HashTable.h"
using namespace js;
using namespace js::gc;
JS_STATIC_ASSERT(AllocKinds == FINALIZE_LIMIT);
JS_STATIC_ASSERT(LastObjectAllocKind == FINALIZE_OBJECT_LAST);
static FILE *gcTraceFile = nullptr;
static HashSet<const Class *, DefaultHasher<const Class *>, SystemAllocPolicy> tracedClasses;
static inline void
WriteWord(uint64_t data)
{
if (gcTraceFile)
fwrite(&data, sizeof(data), 1, gcTraceFile);
}
static inline void
TraceEvent(GCTraceEvent event, uint64_t payload = 0, uint8_t extra = 0)
{
JS_ASSERT(event < GCTraceEventCount);
JS_ASSERT((payload >> TracePayloadBits) == 0);
WriteWord((uint64_t(event) << TraceEventShift) |
(uint64_t(extra) << TraceExtraShift) | payload);
}
static inline void
TraceAddress(const void *p)
{
TraceEvent(TraceDataAddress, uint64_t(p));
}
static inline void
TraceInt(uint32_t data)
{
TraceEvent(TraceDataInt, data);
}
static void
TraceString(const char* string)
{
JS_STATIC_ASSERT(sizeof(char) == 1);
size_t length = strlen(string);
const unsigned charsPerWord = sizeof(uint64_t);
unsigned wordCount = (length + charsPerWord - 1) / charsPerWord;
TraceEvent(TraceDataString, length);
for (unsigned i = 0; i < wordCount; ++i) {
union
{
uint64_t word;
char chars[charsPerWord];
} data;
strncpy(data.chars, string + (i * charsPerWord), charsPerWord);
WriteWord(data.word);
}
}
bool
js::gc::InitTrace(GCRuntime &gc)
{
char *filename = getenv("JS_GC_TRACE");
if (!filename)
return true;
if (!tracedClasses.init())
return false;
/* This currently does not support multiple runtimes. */
JS_ASSERT(!gcTraceFile);
gcTraceFile = fopen(filename, "w");
if (!gcTraceFile)
return false;
TraceEvent(TraceEventInit, 0, TraceFormatVersion);
/* Trace information about thing sizes. */
for (unsigned kind = 0; kind < FINALIZE_LIMIT; ++kind)
TraceEvent(TraceEventThingSize, Arena::thingSize((AllocKind)kind));
return true;
}
void
js::gc::FinishTrace()
{
if (gcTraceFile)
fclose(gcTraceFile);
}
bool
js::gc::TraceEnabled()
{
return gcTraceFile != nullptr;
}
void
js::gc::TraceNurseryAlloc(Cell *thing, size_t size)
{
if (thing) {
/* We don't have AllocKind here, but we can work it out from size. */
unsigned slots = (size - sizeof(JSObject)) / sizeof(JS::Value);
AllocKind kind = GetBackgroundAllocKind(GetGCObjectKind(slots));
TraceEvent(TraceEventNurseryAlloc, uint64_t(thing), kind);
}
}
void
js::gc::TraceTenuredAlloc(Cell *thing, AllocKind kind)
{
if (thing)
TraceEvent(TraceEventTenuredAlloc, uint64_t(thing), kind);
}
static void
MaybeTraceClass(const Class *clasp)
{
if (tracedClasses.has(clasp))
return;
TraceEvent(TraceEventClassInfo, uint64_t(clasp));
TraceInt(clasp->flags);
TraceString(clasp->name);
tracedClasses.put(clasp);
}
void
js::gc::TraceCreateObject(JSObject* object)
{
if (!gcTraceFile)
return;
const Class *clasp = object->type()->clasp();
MaybeTraceClass(clasp);
TraceEvent(TraceEventCreateObject, uint64_t(object));
TraceAddress(clasp);
}
void
js::gc::TraceMinorGCStart()
{
TraceEvent(TraceEventMinorGCStart);
}
void
js::gc::TracePromoteToTenured(Cell *src, Cell *dst)
{
TraceEvent(TraceEventPromoteToTenured, uint64_t(src));
TraceAddress(dst);
}
void
js::gc::TraceMinorGCEnd()
{
TraceEvent(TraceEventMinorGCEnd);
}
void
js::gc::TraceMajorGCStart()
{
TraceEvent(TraceEventMajorGCStart);
}
void
js::gc::TraceTenuredFinalize(Cell *thing)
{
TraceEvent(TraceEventTenuredFinalize, uint64_t(thing));
}
void
js::gc::TraceMajorGCEnd()
{
TraceEvent(TraceEventMajorGCEnd);
}
#endif

53
js/src/gc/GCTrace.h Normal file
View File

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef gc_GCTrace_h
#define gc_GCTrace_h
#include "gc/Heap.h"
namespace js {
namespace types { struct TypeObject; }
namespace gc {
#ifdef JS_GC_TRACE
extern bool InitTrace(GCRuntime &gc);
extern void FinishTrace();
extern bool TraceEnabled();
extern void TraceNurseryAlloc(Cell *thing, size_t size);
extern void TraceTenuredAlloc(Cell *thing, AllocKind kind);
extern void TraceCreateObject(JSObject* object);
extern void TraceMinorGCStart();
extern void TracePromoteToTenured(Cell *src, Cell *dst);
extern void TraceMinorGCEnd();
extern void TraceMajorGCStart();
extern void TraceTenuredFinalize(Cell *thing);
extern void TraceMajorGCEnd();
#else
inline bool InitTrace(GCRuntime &gc) { return true; }
inline void FinishTrace() {}
inline bool TraceEnabled() { return false; }
inline void TraceNurseryAlloc(Cell *thing, size_t size) {}
inline void TraceTenuredAlloc(Cell *thing, AllocKind kind) {}
inline void TraceCreateObject(JSObject* object) {}
inline void TraceMinorGCStart() {}
inline void TracePromoteToTenured(Cell *src, Cell *dst) {}
inline void TraceMinorGCEnd() {}
inline void TraceMajorGCStart() {}
inline void TraceTenuredFinalize(Cell *thing) {}
inline void TraceMajorGCEnd() {}
#endif
} /* namespace gc */
} /* namespace js */
#endif

54
js/src/gc/GCTraceFormat.h Normal file
View File

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef gc_GCTraceFormat_h
#define gc_GCTraceFormat_h
/*
* Each trace is stored as a 64-bit word with the following format:
*
* 56 48 0
* +----------------+----------------+-----------------------------------------+
* | Event type | Optional extra | Optional payload |
* +----------------+----------------+-----------------------------------------+
*/
enum GCTraceEvent {
// Events
TraceEventInit,
TraceEventThingSize,
TraceEventNurseryAlloc,
TraceEventTenuredAlloc,
TraceEventClassInfo,
TraceEventCreateObject,
TraceEventMinorGCStart,
TraceEventPromoteToTenured,
TraceEventMinorGCEnd,
TraceEventMajorGCStart,
TraceEventTenuredFinalize,
TraceEventMajorGCEnd,
TraceDataAddress, // following TraceEventPromote
TraceDataInt, // following TraceEventClassInfo
TraceDataString, // following TraceEventClassInfo
GCTraceEventCount
};
const unsigned TraceFormatVersion = 1;
const unsigned TracePayloadBits = 48;
const unsigned TraceExtraShift = 48;
const unsigned TraceExtraBits = 8;
const unsigned TraceEventShift = 56;
const unsigned TraceEventBits = 8;
const unsigned AllocKinds = 22;
const unsigned LastObjectAllocKind = 11;
#endif

View File

@ -165,6 +165,7 @@ js::Nursery::allocateObject(JSContext *cx, size_t size, size_t numDynamic)
JSObject *obj = static_cast<JSObject *>(allocate(totalSize));
if (obj) {
obj->setInitialSlots(reinterpret_cast<HeapSlot *>(size_t(obj) + size));
TraceNurseryAlloc(obj, size);
return obj;
}
/* If we failed to allocate as a block, retry with out-of-line slots. */
@ -184,6 +185,7 @@ js::Nursery::allocateObject(JSContext *cx, size_t size, size_t numDynamic)
else
freeSlots(cx, slots);
TraceNurseryAlloc(obj, size);
return obj;
}
@ -573,6 +575,7 @@ js::Nursery::moveToTenured(MinorCollectionTracer *trc, JSObject *src)
overlay->forwardTo(dst);
trc->insertIntoFixupList(overlay);
TracePromoteToTenured(src, dst);
return static_cast<void *>(dst);
}
@ -764,6 +767,8 @@ js::Nursery::collect(JSRuntime *rt, JS::gcreason::Reason reason, TypeObjectList
rt->gc.stats.count(gcstats::STAT_MINOR_GC);
TraceMinorGCStart();
TIME_START(total);
AutoStopVerifyingBarriers av(rt, false);
@ -884,6 +889,8 @@ js::Nursery::collect(JSRuntime *rt, JS::gcreason::Reason reason, TypeObjectList
TIME_END(total);
TraceMinorGCEnd();
#ifdef PROFILE_NURSERY
int64_t totalTime = TIME_TOTAL(total);

View File

@ -101,41 +101,41 @@ MarkExactStackRootList(JSTracer *trc, Source *s, const char *name)
}
}
template <class T, void (MarkFunc)(JSTracer *trc, T *ref, const char *name)>
static inline void
MarkExactStackRootsForType(JSRuntime* rt, JSTracer *trc, const char *name = nullptr)
template<class T>
static void
MarkExactStackRootsAcrossTypes(T context, JSTracer *trc)
{
MarkExactStackRootList<JSObject *, MarkObjectRoot>(trc, context, "exact-object");
MarkExactStackRootList<Shape *, MarkShapeRoot>(trc, context, "exact-shape");
MarkExactStackRootList<BaseShape *, MarkBaseShapeRoot>(trc, context, "exact-baseshape");
MarkExactStackRootList<types::TypeObject *, MarkTypeObjectRoot>(
trc, context, "exact-typeobject");
MarkExactStackRootList<JSString *, MarkStringRoot>(trc, context, "exact-string");
MarkExactStackRootList<JS::Symbol *, MarkSymbolRoot>(trc, context, "exact-symbol");
MarkExactStackRootList<jit::JitCode *, MarkJitCodeRoot>(trc, context, "exact-jitcode");
MarkExactStackRootList<JSScript *, MarkScriptRoot>(trc, context, "exact-script");
MarkExactStackRootList<LazyScript *, MarkLazyScriptRoot>(trc, context, "exact-lazy-script");
MarkExactStackRootList<jsid, MarkIdRoot>(trc, context, "exact-id");
MarkExactStackRootList<Value, MarkValueRoot>(trc, context, "exact-value");
MarkExactStackRootList<types::Type, MarkTypeRoot>(trc, context, "types::Type");
MarkExactStackRootList<Bindings, MarkBindingsRoot>(trc, context, "Bindings");
MarkExactStackRootList<JSPropertyDescriptor, MarkPropertyDescriptorRoot>(
trc, context, "JSPropertyDescriptor");
MarkExactStackRootList<PropDesc, MarkPropDescRoot>(trc, context, "PropDesc");
}
static void
MarkExactStackRoots(ThreadSafeContext* cx, JSTracer *trc)
{
MarkExactStackRootsAcrossTypes<ThreadSafeContext*>(cx, trc);
}
static void
MarkExactStackRoots(JSRuntime* rt, JSTracer *trc)
{
for (ContextIter cx(rt); !cx.done(); cx.next())
MarkExactStackRootList<T, MarkFunc>(trc, cx.get(), name);
MarkExactStackRootList<T, MarkFunc>(trc, &rt->mainThread, name);
}
template <class T, void (MarkFunc)(JSTracer *trc, T *ref, const char *name)>
static inline void
MarkExactStackRootsForType(ThreadSafeContext* cx, JSTracer *trc, const char *name = nullptr)
{
MarkExactStackRootList<T, MarkFunc>(trc, cx->perThreadData, name);
}
template <class T>
static void
MarkExactStackRoots(T context, JSTracer *trc)
{
MarkExactStackRootsForType<JSObject *, MarkObjectRoot>(context, trc, "exact-object");
MarkExactStackRootsForType<Shape *, MarkShapeRoot>(context, trc, "exact-shape");
MarkExactStackRootsForType<BaseShape *, MarkBaseShapeRoot>(context, trc, "exact-baseshape");
MarkExactStackRootsForType<types::TypeObject *, MarkTypeObjectRoot>(context, trc, "exact-typeobject");
MarkExactStackRootsForType<JSString *, MarkStringRoot>(context, trc, "exact-string");
MarkExactStackRootsForType<JS::Symbol *, MarkSymbolRoot>(context, trc, "exact-symbol");
MarkExactStackRootsForType<jit::JitCode *, MarkJitCodeRoot>(context, trc, "exact-jitcode");
MarkExactStackRootsForType<JSScript *, MarkScriptRoot>(context, trc, "exact-script");
MarkExactStackRootsForType<LazyScript *, MarkLazyScriptRoot>(context, trc, "exact-lazy-script");
MarkExactStackRootsForType<jsid, MarkIdRoot>(context, trc, "exact-id");
MarkExactStackRootsForType<Value, MarkValueRoot>(context, trc, "exact-value");
MarkExactStackRootsForType<types::Type, MarkTypeRoot>(context, trc, "exact-type");
MarkExactStackRootsForType<Bindings, MarkBindingsRoot>(context, trc);
MarkExactStackRootsForType<JSPropertyDescriptor, MarkPropertyDescriptorRoot>(context, trc);
MarkExactStackRootsForType<PropDesc, MarkPropDescRoot>(context, trc);
MarkExactStackRootsAcrossTypes<ThreadSafeContext*>(cx.get(), trc);
MarkExactStackRootsAcrossTypes<PerThreadData*>(&rt->mainThread, trc);
}
#endif /* JSGC_USE_EXACT_ROOTING */
@ -701,7 +701,7 @@ js::gc::MarkForkJoinStack(ForkJoinNurseryCollectionTracer *trc)
PerThreadData *ptd = cx->perThreadData;
AutoGCRooter::traceAllInContext(cx, trc);
MarkExactStackRoots<ThreadSafeContext*>(cx, trc);
MarkExactStackRoots(cx, trc);
jit::MarkJitActivations(ptd, trc);
#ifdef DEBUG
@ -733,7 +733,7 @@ js::gc::GCRuntime::markRuntime(JSTracer *trc, bool useSavedRoots)
if (!rt->isBeingDestroyed()) {
#ifdef JSGC_USE_EXACT_ROOTING
MarkExactStackRoots<JSRuntime*>(rt, trc);
MarkExactStackRoots(rt, trc);
#else
markConservativeStackRoots(trc, useSavedRoots);
#endif

View File

@ -10,6 +10,7 @@
#include "jsprf.h"
#include "builtin/TypedObject.h"
#include "gc/GCTrace.h"
#include "jit/Bailouts.h"
#include "jit/BaselineFrame.h"
#include "jit/BaselineIC.h"
@ -437,12 +438,16 @@ template void MacroAssembler::loadFromTypedArray(int arrayType, const BaseIndex
void
MacroAssembler::checkAllocatorState(Label *fail)
{
#ifdef JS_GC_ZEAL
// Don't execute the inline path if gcZeal is active.
// Don't execute the inline path if we are tracing allocations.
if (js::gc::TraceEnabled())
jump(fail);
# ifdef JS_GC_ZEAL
// Don't execute the inline path if gc zeal or tracing are active.
branch32(Assembler::NotEqual,
AbsoluteAddress(GetIonContext()->runtime->addressOfGCZeal()), Imm32(0),
fail);
#endif
# endif
// Don't execute the inline path if the compartment has an object metadata callback,
// as the metadata to use for the object may vary between executions of the op.
@ -880,6 +885,21 @@ MacroAssembler::initGCThing(Register obj, Register slots, JSObject *templateObj,
Address(obj, JSObject::getPrivateDataOffset(nfixed)));
}
}
#ifdef JS_GC_TRACE
RegisterSet regs = RegisterSet::Volatile();
PushRegsInMask(regs);
regs.takeUnchecked(obj);
Register temp = regs.takeGeneral();
setupUnalignedABICall(2, temp);
passABIArg(obj);
movePtr(ImmGCPtr(templateObj->type()), temp);
passABIArg(temp);
callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::gc::TraceCreateObject));
PopRegsInMask(RegisterSet::Volatile());
#endif
}
void

View File

@ -2093,16 +2093,15 @@ Assembler::as_vxfer(Register vt1, Register vt2, VFPRegister vm, FloatToCore_ f2c
} else {
JS_ASSERT(idx == 0);
}
VFPXferSize xfersz = WordTransfer;
uint32_t (*encodeVFP)(VFPRegister) = VN;
if (vt2 != InvalidReg) {
// We are doing a 64 bit transfer.
xfersz = DoubleTransfer;
encodeVFP = VM;
}
return writeVFPInst(sz, xfersz | f2c | c |
RT(vt1) | maybeRN(vt2) | encodeVFP(vm) | idx);
if (vt2 == InvalidReg) {
return writeVFPInst(sz, WordTransfer | f2c | c |
RT(vt1) | maybeRN(vt2) | VN(vm) | idx);
} else {
// We are doing a 64 bit transfer.
return writeVFPInst(sz, DoubleTransfer | f2c | c |
RT(vt1) | maybeRN(vt2) | VM(vm) | idx);
}
}
enum vcvt_destFloatness {
toInteger = 1 << 18,

View File

@ -71,8 +71,8 @@ BEGIN_TEST(testChromeBuffer)
JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
JS::CompileOptions options(cx);
options.setFileAndLine("", 0);
CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, &paramName,
bytes, strlen(bytes), options));
CHECK(JS_CompileFunction(cx, global, "trusted", 1, &paramName,
bytes, strlen(bytes), options, &fun));
trusted_fun = JS_GetFunctionObject(fun);
if (!JS::AddNamedObjectRoot(cx, &trusted_fun, "trusted-function"))
return false;
@ -93,8 +93,8 @@ BEGIN_TEST(testChromeBuffer)
"} ";
JS::CompileOptions options(cx);
options.setFileAndLine("", 0);
CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
bytes, strlen(bytes), options));
CHECK(JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
bytes, strlen(bytes), options, &fun));
JS::RootedValue rval(cx);
CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, JS::HandleValueArray(v), &rval));
@ -117,8 +117,8 @@ BEGIN_TEST(testChromeBuffer)
JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
JS::CompileOptions options(cx);
options.setFileAndLine("", 0);
CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, &paramName,
bytes, strlen(bytes), options));
CHECK(JS_CompileFunction(cx, global, "trusted", 1, &paramName,
bytes, strlen(bytes), options, &fun));
trusted_fun = JS_GetFunctionObject(fun);
}
@ -133,8 +133,8 @@ BEGIN_TEST(testChromeBuffer)
"} ";
JS::CompileOptions options(cx);
options.setFileAndLine("", 0);
CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
bytes, strlen(bytes), options));
CHECK(JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
bytes, strlen(bytes), options, &fun));
JS::RootedValue rval(cx);
CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, JS::HandleValueArray(v), &rval));
@ -154,8 +154,8 @@ BEGIN_TEST(testChromeBuffer)
JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
JS::CompileOptions options(cx);
options.setFileAndLine("", 0);
CHECK(fun = JS_CompileFunction(cx, global, "trusted", 0, nullptr,
bytes, strlen(bytes), options));
CHECK(JS_CompileFunction(cx, global, "trusted", 0, nullptr,
bytes, strlen(bytes), options, &fun));
trusted_fun = JS_GetFunctionObject(fun);
}
@ -170,8 +170,8 @@ BEGIN_TEST(testChromeBuffer)
"} ";
JS::CompileOptions options(cx);
options.setFileAndLine("", 0);
CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
bytes, strlen(bytes), options));
CHECK(JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
bytes, strlen(bytes), options, &fun));
JS::RootedValue arg(cx, JS::ObjectValue(*callTrusted));
JS::RootedValue rval(cx);

View File

@ -33,11 +33,11 @@ BEGIN_TEST(test_cloneScript)
// compile for A
{
JSAutoCompartment a(cx, A);
JSFunction *fun;
JS::RootedFunction fun(cx);
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, 1);
CHECK(fun = JS_CompileFunction(cx, A, "f", 0, nullptr, source,
strlen(source), options));
CHECK(JS_CompileFunction(cx, A, "f", 0, nullptr, source,
strlen(source), options, &fun));
CHECK(obj = JS_GetFunctionObject(fun));
}
@ -109,9 +109,10 @@ BEGIN_TEST(test_cloneScriptWithPrincipals)
JSAutoCompartment a(cx, A);
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, 1);
JS::RootedFunction fun(cx, JS_CompileFunction(cx, A, "f",
mozilla::ArrayLength(argnames), argnames, source,
strlen(source), options));
JS::RootedFunction fun(cx);
JS_CompileFunction(cx, A, "f",
mozilla::ArrayLength(argnames), argnames, source,
strlen(source), options, &fun);
CHECK(fun);
JSScript *script;

View File

@ -40,22 +40,22 @@ BEGIN_TEST(test_enclosingFunction)
options.setFileAndLine(__FILE__, __LINE__);
const char s1chars[] = "checkEnclosing()";
fun = JS_CompileFunction(cx, global, "s1", 0, nullptr, s1chars,
strlen(s1chars), options);
JS_CompileFunction(cx, global, "s1", 0, nullptr, s1chars,
strlen(s1chars), options, &fun);
CHECK(fun);
EXEC("s1()");
CHECK(foundFun == fun);
const char s2chars[] = "return function() { checkEnclosing() }";
fun = JS_CompileFunction(cx, global, "s2", 0, nullptr, s2chars,
strlen(s2chars), options);
JS_CompileFunction(cx, global, "s2", 0, nullptr, s2chars,
strlen(s2chars), options, &fun);
CHECK(fun);
EXEC("s2()()");
CHECK(foundFun == fun);
const char s3chars[] = "return function() { let (x) { function g() { checkEnclosing() } return g() } }";
fun = JS_CompileFunction(cx, global, "s3", 0, nullptr, s3chars,
strlen(s3chars), options);
JS_CompileFunction(cx, global, "s3", 0, nullptr, s3chars,
strlen(s3chars), options, &fun);
CHECK(fun);
EXEC("s3()()");
CHECK(foundFun == fun);

View File

@ -29,9 +29,8 @@ BEGIN_TEST(testScriptInfo)
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, startLine);
JS::RootedScript script(cx, JS_CompileScript(cx, global, code, strlen(code),
options));
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, code, strlen(code), options, &script));
CHECK(script);
jsbytecode *start = JS_LineNumberToPC(cx, script, startLine);

View File

@ -18,9 +18,8 @@ struct ScriptObjectFixture : public JSAPITest {
uc_code[i] = code[i];
}
bool tryScript(JS::HandleObject global, JSScript *scriptArg)
bool tryScript(JS::HandleObject global, JS::HandleScript script)
{
JS::RootedScript script(cx, scriptArg);
CHECK(script);
JS_GC(rt);
@ -42,8 +41,9 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript)
{
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
return tryScript(global, JS_CompileScript(cx, global, code, code_size,
options));
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, code, code_size, options, &script));
return tryScript(global, script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript)
@ -51,7 +51,9 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript_empty)
{
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
return tryScript(global, JS_CompileScript(cx, global, "", 0, options));
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, "", 0, options, &script));
return tryScript(global, script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript_empty)
@ -59,8 +61,9 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScriptForPrincipals)
{
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
return tryScript(global, JS_CompileScript(cx, global, code, code_size,
options));
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, code, code_size, options, &script));
return tryScript(global, script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScriptForPrincipals)
@ -68,8 +71,9 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript)
{
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
return tryScript(global, JS_CompileUCScript(cx, global, uc_code, code_size,
options));
JS::RootedScript script(cx);
CHECK(JS_CompileUCScript(cx, global, uc_code, code_size, options, &script));
return tryScript(global, script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript)
@ -77,8 +81,9 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript_empty)
{
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
return tryScript(global, JS_CompileUCScript(cx, global, uc_code, 0,
options));
JS::RootedScript script(cx);
CHECK(JS_CompileUCScript(cx, global, uc_code, 0, options, &script));
return tryScript(global, script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript_empty)
@ -86,8 +91,9 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScriptForPrincipal
{
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
return tryScript(global, JS_CompileUCScript(cx, global, uc_code, code_size,
options));
JS::RootedScript script(cx);
CHECK(JS_CompileUCScript(cx, global, uc_code, code_size, options, &script));
return tryScript(global, script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScriptForPrincipals)
@ -100,7 +106,8 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile)
tempScript.close();
JS::CompileOptions options(cx);
options.setFileAndLine(script_filename, 1);
JSScript *script = JS::Compile(cx, global, options, script_filename);
JS::RootedScript script(cx);
CHECK(JS::Compile(cx, global, options, script_filename, &script));
tempScript.remove();
return tryScript(global, script);
}
@ -114,7 +121,8 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile_empty)
tempScript.close();
JS::CompileOptions options(cx);
options.setFileAndLine(script_filename, 1);
JSScript *script = JS::Compile(cx, global, options, script_filename);
JS::RootedScript script(cx);
CHECK(JS::Compile(cx, global, options, script_filename, &script));
tempScript.remove();
return tryScript(global, script);
}
@ -129,7 +137,9 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle)
CHECK(fseek(script_stream, 0, SEEK_SET) != EOF);
JS::CompileOptions options(cx);
options.setFileAndLine(script_filename, 1);
return tryScript(global, JS::Compile(cx, global, options, script_stream));
JS::RootedScript script(cx);
CHECK(JS::Compile(cx, global, options, script_stream, &script));
return tryScript(global, script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle)
@ -140,7 +150,9 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle_empty)
FILE *script_stream = tempScript.open("temp-bug438633_JS_CompileFileHandle_empty");
JS::CompileOptions options(cx);
options.setFileAndLine(script_filename, 1);
return tryScript(global, JS::Compile(cx, global, options, script_stream));
JS::RootedScript script(cx);
CHECK(JS::Compile(cx, global, options, script_stream, &script));
return tryScript(global, script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandle_empty)
@ -152,6 +164,8 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandleForPrincip
CHECK(fseek(script_stream, 0, SEEK_SET) != EOF);
JS::CompileOptions options(cx);
options.setFileAndLine("temporary file", 1);
return tryScript(global, JS::Compile(cx, global, options, script_stream));
JS::RootedScript script(cx);
CHECK(JS::Compile(cx, global, options, script_stream, &script));
return tryScript(global, script);
}
END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFileHandleForPrincipals)

View File

@ -17,7 +17,9 @@ BEGIN_TEST(testBug795104)
memset(s + 1, 'x', strLen - 2);
s[strLen - 1] = '"';
CHECK(JS::Evaluate(cx, global, opts, s, strLen));
CHECK(JS::CompileFunction(cx, global, opts, "f", 0, nullptr, s, strLen));
JS::RootedFunction fun(cx);
CHECK(JS::CompileFunction(cx, global, opts, "f", 0, nullptr, s, strLen, &fun));
CHECK(fun);
JS_free(cx, s);
return true;

View File

@ -36,8 +36,8 @@ BEGIN_TEST(testTrap_gc)
// compile
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, 1);
JS::RootedScript script(cx, JS_CompileScript(cx, global, source,
strlen(source), options));
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, source, strlen(source), options, &script));
CHECK(script);
// execute

View File

@ -30,7 +30,8 @@ CompileScriptForPrincipalsVersionOrigin(JSContext *cx, JS::HandleObject obj,
options.setOriginPrincipals(originPrincipals)
.setFileAndLine(filename, lineno)
.setVersion(version);
JSScript *script = JS::Compile(cx, obj, options, chars, nchars);
JS::RootedScript script(cx);
JS::Compile(cx, obj, options, chars, nchars, &script);
free(chars);
return script;
}
@ -162,8 +163,8 @@ BEGIN_TEST(testXDR_bug506491)
// compile
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
JS::RootedScript script(cx, JS_CompileScript(cx, global, s, strlen(s),
options));
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, s, strlen(s), options, &script));
CHECK(script);
script = FreezeThaw(cx, script);
@ -189,7 +190,8 @@ BEGIN_TEST(testXDR_bug516827)
// compile an empty script
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
JS::RootedScript script(cx, JS_CompileScript(cx, global, "", 0, options));
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, "", 0, options, &script));
CHECK(script);
script = FreezeThaw(cx, script);
@ -212,8 +214,8 @@ BEGIN_TEST(testXDR_source)
for (const char **s = samples; *s; s++) {
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
JS::RootedScript script(cx, JS_CompileScript(cx, global, *s, strlen(*s),
options));
JS::RootedScript script(cx);
CHECK(JS_CompileScript(cx, global, *s, strlen(*s), options, &script));
CHECK(script);
script = FreezeThaw(cx, script);
CHECK(script);
@ -238,7 +240,7 @@ BEGIN_TEST(testXDR_sourceMap)
for (const char **sm = sourceMaps; *sm; sm++) {
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
script = JS_CompileScript(cx, global, "", 0, options);
CHECK(JS_CompileScript(cx, global, "", 0, options, &script));
CHECK(script);
size_t len = strlen(*sm);

View File

@ -1109,54 +1109,58 @@ JS_TransplantObject(JSContext *cx, HandleObject origobj, HandleObject target)
JS_ASSERT(!origobj->is<CrossCompartmentWrapperObject>());
JS_ASSERT(!target->is<CrossCompartmentWrapperObject>());
AutoMaybeTouchDeadZones agc(cx);
AutoDisableProxyCheck adpc(cx->runtime());
JSCompartment *destination = target->compartment();
RootedValue origv(cx, ObjectValue(*origobj));
RootedObject newIdentity(cx);
if (origobj->compartment() == destination) {
// If the original object is in the same compartment as the
// destination, then we know that we won't find a wrapper in the
// destination's cross compartment map and that the same
// object will continue to work.
if (!JSObject::swap(cx, origobj, target))
MOZ_CRASH();
newIdentity = origobj;
} else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
// There might already be a wrapper for the original object in
// the new compartment. If there is, we use its identity and swap
// in the contents of |target|.
newIdentity = &p->value().get().toObject();
{
// Scope to make ~AutoMaybeTouchDeadZones do its GC before the return value is on the stack.
AutoMaybeTouchDeadZones agc(cx);
AutoDisableProxyCheck adpc(cx->runtime());
// When we remove origv from the wrapper map, its wrapper, newIdentity,
// must immediately cease to be a cross-compartment wrapper. Neuter it.
destination->removeWrapper(p);
NukeCrossCompartmentWrapper(cx, newIdentity);
JSCompartment *destination = target->compartment();
if (!JSObject::swap(cx, newIdentity, target))
MOZ_CRASH();
} else {
// Otherwise, we use |target| for the new identity object.
newIdentity = target;
}
if (origobj->compartment() == destination) {
// If the original object is in the same compartment as the
// destination, then we know that we won't find a wrapper in the
// destination's cross compartment map and that the same
// object will continue to work.
if (!JSObject::swap(cx, origobj, target))
MOZ_CRASH();
newIdentity = origobj;
} else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
// There might already be a wrapper for the original object in
// the new compartment. If there is, we use its identity and swap
// in the contents of |target|.
newIdentity = &p->value().get().toObject();
// Now, iterate through other scopes looking for references to the
// old object, and update the relevant cross-compartment wrappers.
if (!RemapAllWrappersForObject(cx, origobj, newIdentity))
MOZ_CRASH();
// When we remove origv from the wrapper map, its wrapper, newIdentity,
// must immediately cease to be a cross-compartment wrapper. Neuter it.
destination->removeWrapper(p);
NukeCrossCompartmentWrapper(cx, newIdentity);
// Lastly, update the original object to point to the new one.
if (origobj->compartment() != destination) {
RootedObject newIdentityWrapper(cx, newIdentity);
AutoCompartment ac(cx, origobj);
if (!JS_WrapObject(cx, &newIdentityWrapper))
if (!JSObject::swap(cx, newIdentity, target))
MOZ_CRASH();
} else {
// Otherwise, we use |target| for the new identity object.
newIdentity = target;
}
// Now, iterate through other scopes looking for references to the
// old object, and update the relevant cross-compartment wrappers.
if (!RemapAllWrappersForObject(cx, origobj, newIdentity))
MOZ_CRASH();
JS_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
if (!JSObject::swap(cx, origobj, newIdentityWrapper))
MOZ_CRASH();
origobj->compartment()->putWrapper(cx, CrossCompartmentKey(newIdentity), origv);
// Lastly, update the original object to point to the new one.
if (origobj->compartment() != destination) {
RootedObject newIdentityWrapper(cx, newIdentity);
AutoCompartment ac(cx, origobj);
if (!JS_WrapObject(cx, &newIdentityWrapper))
MOZ_CRASH();
JS_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
if (!JSObject::swap(cx, origobj, newIdentityWrapper))
MOZ_CRASH();
origobj->compartment()->putWrapper(cx, CrossCompartmentKey(newIdentity), origv);
}
}
// The new identity object might be one of several things. Return it to avoid
@ -4538,9 +4542,9 @@ JS::CompileOptions::wrap(JSContext *cx, JSCompartment *compartment)
return true;
}
JSScript *
bool
JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
SourceBufferHolder &srcBuf)
SourceBufferHolder &srcBuf, MutableHandleScript script)
{
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
@ -4548,22 +4552,23 @@ JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optio
assertSameCompartment(cx, obj);
AutoLastFrameCheck lfc(cx);
return frontend::CompileScript(cx, &cx->tempLifoAlloc(), obj, NullPtr(), options, srcBuf);
script.set(frontend::CompileScript(cx, &cx->tempLifoAlloc(), obj, NullPtr(), options, srcBuf));
return !!script;
}
JSScript *
bool
JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
const jschar *chars, size_t length)
const jschar *chars, size_t length, MutableHandleScript script)
{
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
return Compile(cx, obj, options, srcBuf);
return Compile(cx, obj, options, srcBuf, script);
}
JSScript *
bool
JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
const char *bytes, size_t length)
const char *bytes, size_t length, MutableHandleScript script)
{
jschar *chars;
mozilla::ScopedFreePtr<jschar> chars;
if (options.utf8)
chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
else
@ -4571,32 +4576,30 @@ JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optio
if (!chars)
return nullptr;
JSScript *script = Compile(cx, obj, options, chars, length);
js_free(chars);
return script;
return Compile(cx, obj, options, chars, length, script);
}
JSScript *
JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, FILE *fp)
bool
JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, FILE *fp,
MutableHandleScript script)
{
FileContents buffer(cx);
if (!ReadCompleteFile(cx, fp, buffer))
return nullptr;
JSScript *script = Compile(cx, obj, options, buffer.begin(), buffer.length());
return script;
return Compile(cx, obj, options, buffer.begin(), buffer.length(), script);
}
JSScript *
JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, const char *filename)
bool
JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, const char *filename,
MutableHandleScript script)
{
AutoFile file;
if (!file.open(cx, filename))
return nullptr;
CompileOptions options(cx, optionsArg);
options.setFileAndLine(filename, 1);
JSScript *script = Compile(cx, obj, options, file.fp());
return script;
return Compile(cx, obj, options, file.fp(), script);
}
JS_PUBLIC_API(bool)
@ -4640,28 +4643,33 @@ JS::FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token)
#ifdef JS_THREADSAFE
JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
Maybe<AutoLastFrameCheck> lfc;
if (maybecx)
lfc.construct(maybecx);
return HelperThreadState().finishParseTask(maybecx, rt, token);
if (maybecx) {
RootedScript script(maybecx);
{
AutoLastFrameCheck lfc(maybecx);
script = HelperThreadState().finishParseTask(maybecx, rt, token);
}
return script;
} else {
return HelperThreadState().finishParseTask(maybecx, rt, token);
}
#else
MOZ_ASSUME_UNREACHABLE("Off thread compilation is not available.");
#endif
}
JS_PUBLIC_API(JSScript *)
JS_PUBLIC_API(bool)
JS_CompileScript(JSContext *cx, JS::HandleObject obj, const char *ascii,
size_t length, const JS::CompileOptions &options)
size_t length, const JS::CompileOptions &options, MutableHandleScript script)
{
return Compile(cx, obj, options, ascii, length);
return Compile(cx, obj, options, ascii, length, script);
}
JS_PUBLIC_API(JSScript *)
JS_PUBLIC_API(bool)
JS_CompileUCScript(JSContext *cx, JS::HandleObject obj, const jschar *chars,
size_t length, const JS::CompileOptions &options)
size_t length, const JS::CompileOptions &options, MutableHandleScript script)
{
return Compile(cx, obj, options, chars, length);
return Compile(cx, obj, options, chars, length, script);
}
JS_PUBLIC_API(bool)
@ -4709,64 +4717,64 @@ JS_GetGlobalFromScript(JSScript *script)
return &script->global();
}
JS_PUBLIC_API(JSFunction *)
JS_PUBLIC_API(bool)
JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
const char *name, unsigned nargs, const char *const *argnames,
SourceBufferHolder &srcBuf)
SourceBufferHolder &srcBuf, MutableHandleFunction fun)
{
JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
RootedAtom funAtom(cx);
AutoLastFrameCheck lfc(cx);
RootedAtom funAtom(cx);
if (name) {
funAtom = Atomize(cx, name, strlen(name));
if (!funAtom)
return nullptr;
return false;
}
AutoNameVector formals(cx);
for (unsigned i = 0; i < nargs; i++) {
RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
if (!argAtom || !formals.append(argAtom->asPropertyName()))
return nullptr;
return false;
}
RootedFunction fun(cx, NewFunction(cx, NullPtr(), nullptr, 0, JSFunction::INTERPRETED, obj,
funAtom, JSFunction::FinalizeKind, TenuredObject));
fun.set(NewFunction(cx, NullPtr(), nullptr, 0, JSFunction::INTERPRETED, obj,
funAtom, JSFunction::FinalizeKind, TenuredObject));
if (!fun)
return nullptr;
return false;
if (!frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf))
return nullptr;
if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf))
return false;
if (obj && funAtom && options.defineOnScope) {
Rooted<jsid> id(cx, AtomToId(funAtom));
RootedValue value(cx, ObjectValue(*fun));
if (!JSObject::defineGeneric(cx, obj, id, value, nullptr, nullptr, JSPROP_ENUMERATE))
return nullptr;
return false;
}
return fun;
return true;
}
JS_PUBLIC_API(JSFunction *)
JS_PUBLIC_API(bool)
JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
const char *name, unsigned nargs, const char *const *argnames,
const jschar *chars, size_t length)
const jschar *chars, size_t length, MutableHandleFunction fun)
{
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
return JS::CompileFunction(cx, obj, options, name, nargs, argnames, srcBuf);
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
return JS::CompileFunction(cx, obj, options, name, nargs, argnames, srcBuf, fun);
}
JS_PUBLIC_API(JSFunction *)
JS_PUBLIC_API(bool)
JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
const char *name, unsigned nargs, const char *const *argnames,
const char *bytes, size_t length)
const char *bytes, size_t length, MutableHandleFunction fun)
{
jschar *chars;
mozilla::ScopedFreePtr<jschar> chars;
if (options.utf8)
chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
else
@ -4774,27 +4782,25 @@ JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOption
if (!chars)
return nullptr;
JSFunction *fun = CompileFunction(cx, obj, options, name, nargs, argnames, chars, length);
js_free(chars);
return fun;
return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length, fun);
}
JS_PUBLIC_API(JSFunction *)
JS_PUBLIC_API(bool)
JS_CompileUCFunction(JSContext *cx, JS::HandleObject obj, const char *name,
unsigned nargs, const char *const *argnames,
const jschar *chars, size_t length,
const CompileOptions &options)
const CompileOptions &options, MutableHandleFunction fun)
{
return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length);
return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length, fun);
}
JS_PUBLIC_API(JSFunction *)
JS_PUBLIC_API(bool)
JS_CompileFunction(JSContext *cx, JS::HandleObject obj, const char *name,
unsigned nargs, const char *const *argnames,
const char *ascii, size_t length,
const JS::CompileOptions &options)
const JS::CompileOptions &options, MutableHandleFunction fun)
{
return CompileFunction(cx, obj, options, name, nargs, argnames, ascii, length);
return CompileFunction(cx, obj, options, name, nargs, argnames, ascii, length, fun);
}
JS_PUBLIC_API(JSString *)
@ -5138,13 +5144,12 @@ JS::Construct(JSContext *cx, HandleValue fval, const JS::HandleValueArray& args,
return InvokeConstructor(cx, fval, args.length(), args.begin(), rval.address());
}
JS_PUBLIC_API(JSObject *)
JS_New(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
static JSObject *
JS_NewHelper(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, ctor, inputArgs);
AutoLastFrameCheck lfc(cx);
// This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
// is not a simple variation of JSOP_CALL. We have to determine what class
@ -5177,6 +5182,17 @@ JS_New(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
return &args.rval().toObject();
}
JS_PUBLIC_API(JSObject *)
JS_New(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
{
RootedObject obj(cx);
{
AutoLastFrameCheck lfc(cx);
obj = JS_NewHelper(cx, ctor, inputArgs);
}
return obj;
}
JS_PUBLIC_API(JSInterruptCallback)
JS_SetInterruptCallback(JSRuntime *rt, JSInterruptCallback callback)
{

View File

@ -3415,30 +3415,46 @@ extern JS_PUBLIC_API(bool)
JS_BufferIsCompilableUnit(JSContext *cx, JS::Handle<JSObject*> obj, const char *utf8,
size_t length);
extern JS_PUBLIC_API(JSScript *)
/*
* |script| will always be set. On failure, it will be set to nullptr.
*/
extern JS_PUBLIC_API(bool)
JS_CompileScript(JSContext *cx, JS::HandleObject obj,
const char *ascii, size_t length,
const JS::CompileOptions &options);
const JS::CompileOptions &options,
JS::MutableHandleScript script);
extern JS_PUBLIC_API(JSScript *)
/*
* |script| will always be set. On failure, it will be set to nullptr.
*/
extern JS_PUBLIC_API(bool)
JS_CompileUCScript(JSContext *cx, JS::HandleObject obj,
const jschar *chars, size_t length,
const JS::CompileOptions &options);
const JS::CompileOptions &options,
JS::MutableHandleScript script);
extern JS_PUBLIC_API(JSObject *)
JS_GetGlobalFromScript(JSScript *script);
extern JS_PUBLIC_API(JSFunction *)
/*
* |fun| will always be set. On failure, it will be set to nullptr.
*/
extern JS_PUBLIC_API(bool)
JS_CompileFunction(JSContext *cx, JS::HandleObject obj, const char *name,
unsigned nargs, const char *const *argnames,
const char *bytes, size_t length,
const JS::CompileOptions &options);
const JS::CompileOptions &options,
JS::MutableHandleFunction fun);
extern JS_PUBLIC_API(JSFunction *)
/*
* |fun| will always be set. On failure, it will be set to nullptr.
*/
extern JS_PUBLIC_API(bool)
JS_CompileUCFunction(JSContext *cx, JS::HandleObject obj, const char *name,
unsigned nargs, const char *const *argnames,
const jschar *chars, size_t length,
const JS::CompileOptions &options);
const JS::CompileOptions &options,
JS::MutableHandleFunction fun);
namespace JS {
@ -3760,23 +3776,28 @@ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOpti
void operator=(const CompileOptions &rhs) MOZ_DELETE;
};
extern JS_PUBLIC_API(JSScript *)
/*
* |script| will always be set. On failure, it will be set to nullptr.
*/
extern JS_PUBLIC_API(bool)
Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options,
const char *bytes, size_t length);
SourceBufferHolder &srcBuf, JS::MutableHandleScript script);
extern JS_PUBLIC_API(JSScript *)
extern JS_PUBLIC_API(bool)
Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options,
const jschar *chars, size_t length);
const char *bytes, size_t length, JS::MutableHandleScript script);
extern JS_PUBLIC_API(JSScript *)
extern JS_PUBLIC_API(bool)
Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options,
SourceBufferHolder &srcBuf);
const jschar *chars, size_t length, JS::MutableHandleScript script);
extern JS_PUBLIC_API(JSScript *)
Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, FILE *file);
extern JS_PUBLIC_API(bool)
Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, FILE *file,
JS::MutableHandleScript script);
extern JS_PUBLIC_API(JSScript *)
Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, const char *filename);
extern JS_PUBLIC_API(bool)
Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, const char *filename,
JS::MutableHandleScript script);
extern JS_PUBLIC_API(bool)
CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, size_t length);
@ -3805,20 +3826,20 @@ CompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options,
extern JS_PUBLIC_API(JSScript *)
FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token);
extern JS_PUBLIC_API(JSFunction *)
extern JS_PUBLIC_API(bool)
CompileFunction(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options,
const char *name, unsigned nargs, const char *const *argnames,
const char *bytes, size_t length);
SourceBufferHolder &srcBuf, JS::MutableHandleFunction fun);
extern JS_PUBLIC_API(JSFunction *)
extern JS_PUBLIC_API(bool)
CompileFunction(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options,
const char *name, unsigned nargs, const char *const *argnames,
const jschar *chars, size_t length);
const char *bytes, size_t length, JS::MutableHandleFunction fun);
extern JS_PUBLIC_API(JSFunction *)
extern JS_PUBLIC_API(bool)
CompileFunction(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options,
const char *name, unsigned nargs, const char *const *argnames,
SourceBufferHolder &srcBuf);
const jschar *chars, size_t length, JS::MutableHandleFunction fun);
} /* namespace JS */

View File

@ -924,7 +924,7 @@ JSCompartment::removeDebuggeeUnderGC(FreeOp *fop,
}
void
JSCompartment::clearBreakpointsIn(FreeOp *fop, js::Debugger *dbg, JSObject *handler)
JSCompartment::clearBreakpointsIn(FreeOp *fop, js::Debugger *dbg, HandleObject handler)
{
for (gc::ZoneCellIter i(zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();

View File

@ -425,7 +425,7 @@ struct JSCompartment
bool setDebugModeFromC(JSContext *cx, bool b,
js::AutoDebugModeInvalidation &invalidate);
void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JSObject *handler);
void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JS::HandleObject handler);
void clearTraps(js::FreeOp *fop);
private:

View File

@ -54,7 +54,6 @@ using namespace js::frontend;
using mozilla::ArrayLength;
using mozilla::PodCopy;
using mozilla::Range;
using mozilla::RangedPtr;
static bool
@ -765,7 +764,7 @@ js::FindBody(JSContext *cx, HandleFunction fun, HandleLinearString src, size_t *
if (!stableChars.initTwoByte(cx, src))
return false;
const Range<const jschar> srcChars = stableChars.twoByteRange();
const mozilla::Range<const jschar> srcChars = stableChars.twoByteRange();
TokenStream ts(cx, options, srcChars.start().get(), srcChars.length(), nullptr);
int nest = 0;
bool onward = true;
@ -1542,7 +1541,7 @@ FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind gener
bool isStarGenerator = generatorKind == StarGenerator;
JS_ASSERT(generatorKind != LegacyGenerator);
JSScript *maybeScript = nullptr;
RootedScript maybeScript(cx);
const char *filename;
unsigned lineno;
JSPrincipals *originPrincipals;
@ -1741,7 +1740,7 @@ FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind gener
if (!stableChars.initTwoByte(cx, str))
return false;
Range<const jschar> chars = stableChars.twoByteRange();
mozilla::Range<const jschar> chars = stableChars.twoByteRange();
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership;

View File

@ -201,6 +201,7 @@
#include "gc/FindSCCs.h"
#include "gc/GCInternals.h"
#include "gc/GCTrace.h"
#include "gc/Marking.h"
#include "gc/Memory.h"
#ifdef JS_ION
@ -490,6 +491,7 @@ Arena::finalize(FreeOp *fop, AllocKind thingKind, size_t thingSize)
} else {
t->finalize(fop);
JS_POISON(t, JS_SWEPT_TENURED_PATTERN, thingSize);
TraceTenuredFinalize(t);
}
}
@ -1280,6 +1282,9 @@ GCRuntime::init(uint32_t maxbytes)
return false;
#endif
if (!InitTrace(*this))
return false;
if (!marker.init(mode))
return false;
@ -1343,6 +1348,8 @@ GCRuntime::finish()
lock = nullptr;
}
#endif
FinishTrace();
}
void
@ -3000,7 +3007,8 @@ PurgeRuntime(JSRuntime *rt)
}
bool
GCRuntime::shouldPreserveJITCode(JSCompartment *comp, int64_t currentTime)
GCRuntime::shouldPreserveJITCode(JSCompartment *comp, int64_t currentTime,
JS::gcreason::Reason reason)
{
if (cleanUpEverything)
return false;
@ -3009,6 +3017,8 @@ GCRuntime::shouldPreserveJITCode(JSCompartment *comp, int64_t currentTime)
return true;
if (comp->lastAnimationTime + PRMJ_USEC_PER_SEC >= currentTime)
return true;
if (reason == JS::gcreason::DEBUG_GC)
return true;
#ifdef JS_ION
if (comp->jitCompartment() && comp->jitCompartment()->hasRecentParallelActivity())
@ -3119,7 +3129,7 @@ GCRuntime::checkForCompartmentMismatches()
#endif
bool
GCRuntime::beginMarkPhase()
GCRuntime::beginMarkPhase(JS::gcreason::Reason reason)
{
int64_t currentTime = PRMJ_Now();
@ -3156,7 +3166,7 @@ GCRuntime::beginMarkPhase()
for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) {
JS_ASSERT(c->gcLiveArrayBuffers.empty());
c->marked = false;
if (shouldPreserveJITCode(c, currentTime))
if (shouldPreserveJITCode(c, currentTime, reason))
c->zone()->setPreservingCode(true);
}
@ -4256,7 +4266,7 @@ GCRuntime::beginSweepPhase(bool lastGC)
gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP);
#ifdef JS_THREADSAFE
sweepOnBackgroundThread = !lastGC;
sweepOnBackgroundThread = !lastGC && !TraceEnabled();
#endif
#ifdef DEBUG
@ -4772,7 +4782,7 @@ GCRuntime::incrementalCollectSlice(int64_t budget,
switch (incrementalState) {
case MARK_ROOTS:
if (!beginMarkPhase()) {
if (!beginMarkPhase(reason)) {
incrementalState = NO_INCREMENTAL;
return;
}
@ -4965,6 +4975,8 @@ GCRuntime::gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
if (prevState != NO_INCREMENTAL && incrementalState == NO_INCREMENTAL)
return true;
TraceMajorGCStart();
incrementalCollectSlice(budget, reason, gckind);
#ifndef JS_MORE_DETERMINISTIC
@ -4986,6 +4998,8 @@ GCRuntime::gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
resetMallocBytes();
TraceMajorGCEnd();
return false;
}

View File

@ -9,6 +9,7 @@
#include "jsgc.h"
#include "gc/GCTrace.h"
#include "gc/Zone.h"
#include "vm/ForkJoin.h"
@ -649,6 +650,7 @@ AllocateObject(ThreadSafeContext *cx, AllocKind kind, size_t nDynamicSlots, Init
js_free(slots);
CheckIncrementalZoneState(cx, obj);
js::gc::TraceTenuredAlloc(obj, kind);
return obj;
}
@ -671,6 +673,7 @@ AllocateNonObject(ThreadSafeContext *cx)
t = static_cast<T *>(js::gc::ArenaLists::refillFreeList<allowGC>(cx, kind));
CheckIncrementalZoneState(cx, t);
js::gc::TraceTenuredAlloc(t, kind);
return t;
}

View File

@ -45,7 +45,6 @@ using mozilla::MinNumberValue;
using mozilla::NegativeInfinity;
using mozilla::PodCopy;
using mozilla::PositiveInfinity;
using mozilla::Range;
using mozilla::RangedPtr;
using JS::AutoCheckCannotGC;
@ -178,7 +177,7 @@ ComputeAccurateBinaryBaseInteger(const CharT *start, const CharT *end, int base)
template <typename CharT>
double
js::ParseDecimalNumber(const Range<const CharT> chars)
js::ParseDecimalNumber(const mozilla::Range<const CharT> chars)
{
MOZ_ASSERT(chars.length() > 0);
uint64_t dec = 0;
@ -196,10 +195,10 @@ js::ParseDecimalNumber(const Range<const CharT> chars)
}
template double
js::ParseDecimalNumber(const Range<const Latin1Char> chars);
js::ParseDecimalNumber(const mozilla::Range<const Latin1Char> chars);
template double
js::ParseDecimalNumber(const Range<const jschar> chars);
js::ParseDecimalNumber(const mozilla::Range<const jschar> chars);
template <typename CharT>
bool

View File

@ -535,6 +535,8 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
if (span)
obj->initializeSlotRange(0, span);
js::gc::TraceCreateObject(obj);
return obj;
}
@ -570,6 +572,8 @@ JSObject::createArray(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::
if (span)
obj->initializeSlotRange(0, span);
js::gc::TraceCreateObject(obj);
return &obj->as<js::ArrayObject>();
}

View File

@ -32,7 +32,6 @@ using namespace js::types;
using mozilla::IsFinite;
using mozilla::Maybe;
using mozilla::Range;
using mozilla::RangedPtr;
const Class js::JSONClass = {
@ -797,7 +796,7 @@ Revive(JSContext *cx, HandleValue reviver, MutableHandleValue vp)
template <typename CharT>
bool
js::ParseJSONWithReviver(JSContext *cx, const Range<const CharT> chars, HandleValue reviver,
js::ParseJSONWithReviver(JSContext *cx, const mozilla::Range<const CharT> chars, HandleValue reviver,
MutableHandleValue vp)
{
/* 15.12.2 steps 2-3. */
@ -812,11 +811,11 @@ js::ParseJSONWithReviver(JSContext *cx, const Range<const CharT> chars, HandleVa
}
template bool
js::ParseJSONWithReviver(JSContext *cx, const Range<const Latin1Char> chars, HandleValue reviver,
MutableHandleValue vp);
js::ParseJSONWithReviver(JSContext *cx, const mozilla::Range<const Latin1Char> chars,
HandleValue reviver, MutableHandleValue vp);
template bool
js::ParseJSONWithReviver(JSContext *cx, const Range<const jschar> chars, HandleValue reviver,
js::ParseJSONWithReviver(JSContext *cx, const mozilla::Range<const jschar> chars, HandleValue reviver,
MutableHandleValue vp);
#if JS_HAS_TOSOURCE

View File

@ -22,7 +22,6 @@
using namespace js;
using mozilla::Range;
using mozilla::RangedPtr;
JSONParserBase::~JSONParserBase()
@ -277,7 +276,7 @@ JSONParser<CharT>::readNumber()
/* Fast path: no fractional or exponent part. */
if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) {
Range<const CharT> chars(digitStart.get(), current - digitStart);
mozilla::Range<const CharT> chars(digitStart.get(), current - digitStart);
if (chars.length() < strlen("9007199254740992")) {
// If the decimal number is shorter than the length of 2**53, (the
// largest number a double can represent with integral precision),

View File

@ -2884,29 +2884,29 @@ js_GetScriptLineExtent(JSScript *script)
}
void
js::DescribeScriptedCallerForCompilation(JSContext *cx, JSScript **maybeScript,
js::DescribeScriptedCallerForCompilation(JSContext *cx, MutableHandleScript maybeScript,
const char **file, unsigned *linenop,
uint32_t *pcOffset, JSPrincipals **origin,
LineOption opt)
{
if (opt == CALLED_FROM_JSOP_EVAL) {
jsbytecode *pc = nullptr;
*maybeScript = cx->currentScript(&pc);
maybeScript.set(cx->currentScript(&pc));
JS_ASSERT(JSOp(*pc) == JSOP_EVAL || JSOp(*pc) == JSOP_SPREADEVAL);
JS_ASSERT(*(pc + (JSOp(*pc) == JSOP_EVAL ? JSOP_EVAL_LENGTH
: JSOP_SPREADEVAL_LENGTH)) == JSOP_LINENO);
*file = (*maybeScript)->filename();
*file = maybeScript->filename();
*linenop = GET_UINT16(pc + (JSOp(*pc) == JSOP_EVAL ? JSOP_EVAL_LENGTH
: JSOP_SPREADEVAL_LENGTH));
*pcOffset = pc - (*maybeScript)->code();
*origin = (*maybeScript)->originPrincipals();
*pcOffset = pc - maybeScript->code();
*origin = maybeScript->originPrincipals();
return;
}
NonBuiltinFrameIter iter(cx);
if (iter.done()) {
*maybeScript = nullptr;
maybeScript.set(nullptr);
*file = nullptr;
*linenop = 0;
*pcOffset = 0;
@ -2921,10 +2921,10 @@ js::DescribeScriptedCallerForCompilation(JSContext *cx, JSScript **maybeScript,
// These values are only used for introducer fields which are debugging
// information and can be safely left null for asm.js frames.
if (iter.hasScript()) {
*maybeScript = iter.script();
*pcOffset = iter.pc() - (*maybeScript)->code();
maybeScript.set(iter.script());
*pcOffset = iter.pc() - maybeScript->code();
} else {
*maybeScript = nullptr;
maybeScript.set(nullptr);
*pcOffset = 0;
}
}

View File

@ -2023,7 +2023,7 @@ enum LineOption {
};
extern void
DescribeScriptedCallerForCompilation(JSContext *cx, JSScript **maybeScript,
DescribeScriptedCallerForCompilation(JSContext *cx, MutableHandleScript maybeScript,
const char **file, unsigned *linenop,
uint32_t *pcOffset, JSPrincipals **origin,
LineOption opt = NOT_CALLED_FROM_JSOP_EVAL);

View File

@ -75,7 +75,6 @@ using mozilla::IsNegativeZero;
using mozilla::IsSame;
using mozilla::PodCopy;
using mozilla::PodEqual;
using mozilla::Range;
using mozilla::RangedPtr;
using mozilla::SafeCast;
@ -244,7 +243,7 @@ Unhex2(const RangedPtr<const CharT> chars, jschar *result)
template <typename CharT>
static bool
Unescape(StringBuffer &sb, const Range<const CharT> chars)
Unescape(StringBuffer &sb, const mozilla::Range<const CharT> chars)
{
/*
* NB: use signed integers for length/index to allow simple length
@ -4343,7 +4342,7 @@ CanStoreCharsAsLatin1(const Latin1Char *s, size_t length)
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE JSInlineString *
NewFatInlineStringDeflated(ThreadSafeContext *cx, Range<const jschar> chars)
NewFatInlineStringDeflated(ThreadSafeContext *cx, mozilla::Range<const jschar> chars)
{
MOZ_ASSERT(EnableLatin1Strings);
@ -4368,7 +4367,7 @@ NewStringDeflated(ThreadSafeContext *cx, const jschar *s, size_t n)
MOZ_ASSERT(EnableLatin1Strings);
if (JSFatInlineString::latin1LengthFits(n))
return NewFatInlineStringDeflated<allowGC>(cx, Range<const jschar>(s, n));
return NewFatInlineStringDeflated<allowGC>(cx, mozilla::Range<const jschar>(s, n));
ScopedJSFreePtr<Latin1Char> news(cx->pod_malloc<Latin1Char>(n + 1));
if (!news)
@ -4469,7 +4468,7 @@ NewStringCopyNDontDeflate(ThreadSafeContext *cx, const CharT *s, size_t n)
{
if (EnableLatin1Strings) {
if (JSFatInlineString::lengthFits<CharT>(n))
return NewFatInlineString<allowGC>(cx, Range<const CharT>(s, n));
return NewFatInlineString<allowGC>(cx, mozilla::Range<const CharT>(s, n));
ScopedJSFreePtr<CharT> news(cx->pod_malloc<CharT>(n + 1));
if (!news)
@ -4487,7 +4486,7 @@ NewStringCopyNDontDeflate(ThreadSafeContext *cx, const CharT *s, size_t n)
}
if (JSFatInlineString::twoByteLengthFits(n))
return NewFatInlineString<allowGC>(cx, Range<const CharT>(s, n));
return NewFatInlineString<allowGC>(cx, mozilla::Range<const CharT>(s, n));
ScopedJSFreePtr<jschar> news(cx->pod_malloc<jschar>(n + 1));
if (!news)

View File

@ -116,6 +116,7 @@ UNIFIED_SOURCES += [
'frontend/TokenStream.cpp',
'gc/Barrier.cpp',
'gc/ForkJoinNursery.cpp',
'gc/GCTrace.cpp',
'gc/Iteration.cpp',
'gc/Marking.cpp',
'gc/Memory.cpp',

View File

@ -86,7 +86,6 @@ using mozilla::ArrayLength;
using mozilla::NumberEqualsInt32;
using mozilla::Maybe;
using mozilla::PodCopy;
using mozilla::Range;
enum JSShellExitCode {
EXITCODE_RUNTIME_ERROR = 3,
@ -437,7 +436,7 @@ RunFile(JSContext *cx, Handle<JSObject*> obj, const char *filename, FILE *file,
.setCompileAndGo(true);
gGotError = false;
script = JS::Compile(cx, obj, options, file);
(void) JS::Compile(cx, obj, options, file, &script);
JS_ASSERT_IF(!script, gGotError);
}
@ -467,8 +466,7 @@ EvalAndPrint(JSContext *cx, Handle<JSObject*> global, const char *bytes, size_t
.setCompileAndGo(true)
.setFileAndLine("typein", lineno);
RootedScript script(cx);
script = JS::Compile(cx, global, options, bytes, length);
if (!script)
if (!JS::Compile(cx, global, options, bytes, length, &script))
return false;
if (compileOnly)
return true;
@ -856,7 +854,8 @@ LoadScript(JSContext *cx, unsigned argc, jsval *vp, bool scriptRelative)
.setUTF8(true)
.setCompileAndGo(true)
.setNoScriptRval(true);
if ((compileOnly && !Compile(cx, thisobj, opts, filename.ptr())) ||
RootedScript script(cx);
if ((compileOnly && !Compile(cx, thisobj, opts, filename.ptr(), &script)) ||
!Evaluate(cx, thisobj, opts, filename.ptr()))
{
return false;
@ -1268,8 +1267,8 @@ Evaluate(JSContext *cx, unsigned argc, jsval *vp)
if (loadBytecode) {
script = JS_DecodeScript(cx, loadBuffer, loadLength, options.originPrincipals(cx));
} else {
Range<const jschar> chars = codeChars.twoByteRange();
script = JS::Compile(cx, global, options, chars.start().get(), chars.length());
mozilla::Range<const jschar> chars = codeChars.twoByteRange();
(void) JS::Compile(cx, global, options, chars.start().get(), chars.length(), &script);
}
if (!script)
@ -1472,8 +1471,7 @@ Run(JSContext *cx, unsigned argc, jsval *vp)
options.setIntroductionType("js shell run")
.setFileAndLine(filename.ptr(), 1)
.setCompileAndGo(true);
script = JS_CompileUCScript(cx, thisobj, ucbuf, buflen, options);
if (!script)
if (!JS_CompileUCScript(cx, thisobj, ucbuf, buflen, options, &script))
return false;
}
@ -1810,7 +1808,7 @@ TrapHandler(JSContext *cx, JSScript *, jsbytecode *pc, jsval *rvalArg,
if (!stableChars.initTwoByte(cx, str))
return JSTRAP_ERROR;
Range<const jschar> chars = stableChars.twoByteRange();
mozilla::Range<const jschar> chars = stableChars.twoByteRange();
if (!frame.evaluateUCInStackFrame(cx, chars.start().get(), chars.length(),
script->filename(),
script->lineno(),
@ -2319,8 +2317,7 @@ DisassFile(JSContext *cx, unsigned argc, jsval *vp)
.setFileAndLine(filename.ptr(), 1)
.setCompileAndGo(true);
script = JS::Compile(cx, thisobj, options, filename.ptr());
if (!script)
if (!JS::Compile(cx, thisobj, options, filename.ptr(), &script))
return false;
}
@ -2532,7 +2529,7 @@ Intern(JSContext *cx, unsigned argc, jsval *vp)
if (!strChars.initTwoByte(cx, str))
return false;
Range<const jschar> chars = strChars.twoByteRange();
mozilla::Range<const jschar> chars = strChars.twoByteRange();
if (!JS_InternUCStringN(cx, chars.start().get(), chars.length()))
return false;
@ -2767,7 +2764,7 @@ EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
if (!strChars.initTwoByte(cx, str))
return false;
Range<const jschar> chars = strChars.twoByteRange();
mozilla::Range<const jschar> chars = strChars.twoByteRange();
size_t srclen = chars.length();
const jschar *src = chars.start().get();
@ -2865,7 +2862,7 @@ EvalInFrame(JSContext *cx, unsigned argc, jsval *vp)
if (!stableChars.initTwoByte(cx, str))
return JSTRAP_ERROR;
Range<const jschar> chars = stableChars.twoByteRange();
mozilla::Range<const jschar> chars = stableChars.twoByteRange();
JSAbstractFramePtr frame(fi.abstractFramePtr().raw(), fi.pc());
RootedScript fpscript(cx, frame.script());
bool ok = !!frame.evaluateUCInStackFrame(cx, chars.start().get(), chars.length(),
@ -2925,9 +2922,8 @@ WorkerMain(void *arg)
options.setFileAndLine("<string>", 1)
.setCompileAndGo(true);
RootedScript script(cx, JS::Compile(cx, global, options,
input->chars, input->length));
if (!script)
RootedScript script(cx);
if (!JS::Compile(cx, global, options, input->chars, input->length, &script))
break;
RootedValue result(cx);
JS_ExecuteScript(cx, global, script, &result);
@ -3560,10 +3556,10 @@ Compile(JSContext *cx, unsigned argc, jsval *vp)
options.setIntroductionType("js shell compile")
.setFileAndLine("<string>", 1)
.setCompileAndGo(true);
RootedScript script(cx);
const jschar *chars = stableChars.twoByteRange().start().get();
bool ok = JS_CompileUCScript(cx, global, chars,
scriptContents->length(), options);
scriptContents->length(), options, &script);
args.rval().setUndefined();
return ok;
}

View File

@ -13,10 +13,9 @@
using namespace JS;
using mozilla::Range;
Latin1CharsZ
JS::LossyTwoByteCharsToNewLatin1CharsZ(js::ThreadSafeContext *cx, const Range<const jschar> tbchars)
JS::LossyTwoByteCharsToNewLatin1CharsZ(js::ThreadSafeContext *cx,
const mozilla::Range<const jschar> tbchars)
{
JS_ASSERT(cx);
size_t len = tbchars.length();
@ -144,7 +143,7 @@ bufferTooSmall:
template <typename CharT>
UTF8CharsZ
JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const Range<const CharT> chars)
JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const mozilla::Range<const CharT> chars)
{
JS_ASSERT(cx);
@ -165,10 +164,10 @@ JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const Range<const CharT> cha
}
template UTF8CharsZ
JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const Range<const Latin1Char> chars);
JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const mozilla::Range<const Latin1Char> chars);
template UTF8CharsZ
JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const Range<const jschar> chars);
JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const mozilla::Range<const jschar> chars);
static const uint32_t INVALID_UTF8 = UINT32_MAX;

View File

@ -2197,7 +2197,7 @@ Debugger::clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp)
THIS_DEBUGGER(cx, argc, vp, "clearAllBreakpoints", args, dbg);
for (GlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront())
r.front()->compartment()->clearBreakpointsIn(cx->runtime()->defaultFreeOp(),
dbg, nullptr);
dbg, NullPtr());
return true;
}

View File

@ -2201,7 +2201,7 @@ class ParallelSpewer
if (cx) {
jsbytecode *pc;
JSScript *script = cx->currentScript(&pc);
RootedScript script(cx, cx->currentScript(&pc));
if (script && pc) {
NonBuiltinScriptFrameIter iter(cx);
if (iter.done()) {

View File

@ -73,6 +73,7 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi
if (obj) {
copyCachedToObject(obj, templateObj, entry->kind);
probes::CreateObject(cx, obj);
js::gc::TraceCreateObject(obj);
return obj;
}

View File

@ -1010,8 +1010,8 @@ JSRuntime::initSelfHosting(JSContext *cx)
char *filename = getenv("MOZ_SELFHOSTEDJS");
if (filename) {
RootedScript script(cx, Compile(cx, shg, options, filename));
if (script)
RootedScript script(cx);
if (Compile(cx, shg, options, filename, &script))
ok = Execute(cx, script, *shg.get(), rv.address());
} else {
uint32_t srcLen = GetRawScriptsSize();

View File

@ -16,6 +16,7 @@
#include "jit/BaselineFrame.h"
#include "jit/JitCompartment.h"
#endif
#include "js/GCAPI.h"
#include "vm/Opcodes.h"
#include "jit/JitFrameIterator-inl.h"
@ -31,7 +32,7 @@ using mozilla::PodCopy;
void
InterpreterFrame::initExecuteFrame(JSContext *cx, JSScript *script, AbstractFramePtr evalInFramePrev,
const Value &thisv, JSObject &scopeChain, ExecuteType type)
const Value &thisv, JSObject &scopeChain, ExecuteType type)
{
/*
* See encoding of ExecuteType. When GLOBAL isn't set, we are executing a
@ -666,6 +667,8 @@ FrameIter::FrameIter(ThreadSafeContext *cx, SavedOption savedOption)
, ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
#endif
{
// settleOnActivation can only GC if principals are given.
JS::AutoSuppressGCAnalysis nogc;
settleOnActivation();
}
@ -676,6 +679,8 @@ FrameIter::FrameIter(ThreadSafeContext *cx, ContextOption contextOption,
, ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
#endif
{
// settleOnActivation can only GC if principals are given.
JS::AutoSuppressGCAnalysis nogc;
settleOnActivation();
}

View File

@ -1090,6 +1090,11 @@ class MOZ_STACK_CLASS AutoStableStringChars
bool isLatin1() const { return state_ == Latin1; }
bool isTwoByte() const { return state_ == TwoByte; }
const jschar *twoByteChars() const {
MOZ_ASSERT(state_ == TwoByte);
return twoByteChars_;
}
mozilla::Range<const Latin1Char> latin1Range() const {
MOZ_ASSERT(state_ == Latin1);
return mozilla::Range<const Latin1Char>(latin1Chars_, s_->length());

View File

@ -14,8 +14,6 @@
using namespace js;
using mozilla::Range;
template <typename CharT, class Buffer>
static CharT *
ExtractWellSized(ExclusiveContext *cx, Buffer &cb)
@ -99,11 +97,15 @@ StringBuffer::finishString()
JS_STATIC_ASSERT(JSFatInlineString::MAX_LENGTH_LATIN1 < Latin1CharBuffer::InlineLength);
if (isLatin1()) {
if (JSFatInlineString::latin1LengthFits(len))
return NewFatInlineString<CanGC>(cx, Range<const Latin1Char>(latin1Chars().begin(), len));
if (JSFatInlineString::latin1LengthFits(len)) {
mozilla::Range<const Latin1Char> range(latin1Chars().begin(), len);
return NewFatInlineString<CanGC>(cx, range);
}
} else {
if (JSFatInlineString::twoByteLengthFits(len))
return NewFatInlineString<CanGC>(cx, Range<const jschar>(twoByteChars().begin(), len));
if (JSFatInlineString::twoByteLengthFits(len)) {
mozilla::Range<const jschar> range(twoByteChars().begin(), len);
return NewFatInlineString<CanGC>(cx, range);
}
}
return isLatin1()

View File

@ -901,12 +901,11 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo &aInfo,
}
if (!mReuseLoaderGlobal) {
script = Compile(cx, obj, options, buf,
fileSize32);
Compile(cx, obj, options, buf, fileSize32, &script);
} else {
function = CompileFunction(cx, obj, options,
nullptr, 0, nullptr,
buf, fileSize32);
CompileFunction(cx, obj, options,
nullptr, 0, nullptr,
buf, fileSize32, &function);
}
PR_MemUnmap(buf, fileSize32);
@ -988,11 +987,11 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo &aInfo,
buf[len] = '\0';
if (!mReuseLoaderGlobal) {
script = Compile(cx, obj, options, buf, bytesRead);
Compile(cx, obj, options, buf, bytesRead, &script);
} else {
function = CompileFunction(cx, obj, options,
nullptr, 0, nullptr,
buf, bytesRead);
CompileFunction(cx, obj, options,
nullptr, 0, nullptr,
buf, bytesRead, &function);
}
}
// Propagate the exception, if one exists. Also, don't leave the stale

View File

@ -95,13 +95,13 @@ nsresult
mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObjArg,
const nsAString &charset, const char *uriStr,
nsIIOService *serv, nsIPrincipal *principal,
bool reuseGlobal, JSScript **scriptp,
JSFunction **functionp)
bool reuseGlobal, JS::MutableHandleScript script,
JS::MutableHandleFunction function)
{
RootedObject target_obj(cx, targetObjArg);
*scriptp = nullptr;
*functionp = nullptr;
script.set(nullptr);
function.set(nullptr);
// Instead of calling NS_OpenURI, we create the channel ourselves and call
// SetContentType, to avoid expensive MIME type lookups (bug 632490).
@ -155,22 +155,23 @@ mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObj
}
if (!reuseGlobal) {
*scriptp = JS::Compile(cx, target_obj, options, srcBuf);
JS::Compile(cx, target_obj, options, srcBuf, script);
} else {
*functionp = JS::CompileFunction(cx, target_obj, options,
nullptr, 0, nullptr,
srcBuf);
JS::CompileFunction(cx, target_obj, options,
nullptr, 0, nullptr,
srcBuf,
function);
}
} else {
// We only use lazy source when no special encoding is specified because
// the lazy source loader doesn't know the encoding.
if (!reuseGlobal) {
options.setSourceIsLazy(true);
*scriptp = JS::Compile(cx, target_obj, options, buf.get(), len);
JS::Compile(cx, target_obj, options, buf.get(), len, script);
} else {
*functionp = JS::CompileFunction(cx, target_obj, options,
nullptr, 0, nullptr, buf.get(),
len);
JS::CompileFunction(cx, target_obj, options,
nullptr, 0, nullptr, buf.get(),
len, function);
}
}
@ -333,7 +334,7 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString &url,
if (!script) {
rv = ReadScript(uri, cx, targetObj, options.charset,
static_cast<const char*>(uriStr.get()), serv,
principal, reusingGlobal, script.address(), function.address());
principal, reusingGlobal, &script, &function);
writeScript = !!script;
}

View File

@ -36,8 +36,8 @@ private:
nsresult ReadScript(nsIURI *uri, JSContext *cx, JSObject *target_obj,
const nsAString &charset, const char *uriStr,
nsIIOService *serv, nsIPrincipal *principal,
bool reuseGlobal, JSScript **scriptp,
JSFunction **functionp);
bool reuseGlobal, JS::MutableHandleScript script,
JS::MutableHandleFunction function);
nsresult DoLoadSubScriptWithOptions(const nsAString &url,
LoadSubScriptOptions &options,

View File

@ -3174,8 +3174,8 @@ nsXPCComponents_Utils::GetComponentsForScope(HandleValue vscope, JSContext *cx,
return NS_ERROR_INVALID_ARG;
JSObject *scopeObj = js::UncheckedUnwrap(&vscope.toObject());
XPCWrappedNativeScope *scope = GetObjectScope(scopeObj);
RootedObject components(cx, scope->GetComponentsJSObject());
if (!components)
RootedObject components(cx);
if (!scope->GetComponentsJSObject(&components))
return NS_ERROR_FAILURE;
if (!JS_WrapObject(cx, &components))
return NS_ERROR_FAILURE;

View File

@ -526,7 +526,7 @@ bool
IsInAddonScope(JSObject *obj)
{
// We always eagerly create compartment privates for addon scopes.
XPCWrappedNativeScope *scope = GetObjectScope(obj);
XPCWrappedNativeScope *scope = MaybeGetObjectScope(obj);
return scope && scope->IsAddonScope();
}

View File

@ -340,7 +340,8 @@ Load(JSContext *cx, unsigned argc, jsval *vp)
JS::CompileOptions options(cx);
options.setUTF8(true)
.setFileAndLine(filename.ptr(), 1);
JS::Rooted<JSScript*> script(cx, JS::Compile(cx, obj, options, file));
JS::Rooted<JSScript*> script(cx);
JS::Compile(cx, obj, options, file, &script);
fclose(file);
if (!script)
return false;
@ -924,8 +925,7 @@ ProcessFile(JSContext *cx, JS::Handle<JSObject*> obj, const char *filename, FILE
JS::CompileOptions options(cx);
options.setUTF8(true)
.setFileAndLine(filename, 1);
script = JS::Compile(cx, obj, options, file);
if (script && !compileOnly)
if (JS::Compile(cx, obj, options, file, &script) && !compileOnly)
(void)JS_ExecuteScript(cx, obj, script, &result);
DoEndRequest(cx);
@ -960,8 +960,7 @@ ProcessFile(JSContext *cx, JS::Handle<JSObject*> obj, const char *filename, FILE
JS_ClearPendingException(cx);
JS::CompileOptions options(cx);
options.setFileAndLine("typein", startline);
script = JS_CompileScript(cx, obj, buffer, strlen(buffer), options);
if (script) {
if (JS_CompileScript(cx, obj, buffer, strlen(buffer), options, &script)) {
JSErrorReporter older;
if (!compileOnly) {

View File

@ -128,8 +128,8 @@ XPCWrappedNativeScope::IsDyingScope(XPCWrappedNativeScope *scope)
return false;
}
JSObject*
XPCWrappedNativeScope::GetComponentsJSObject()
bool
XPCWrappedNativeScope::GetComponentsJSObject(JS::MutableHandleObject obj)
{
AutoJSContext cx;
if (!mComponents) {
@ -145,17 +145,17 @@ XPCWrappedNativeScope::GetComponentsJSObject()
nullptr, nullptr, false,
nullptr);
if (NS_WARN_IF(!ok))
return nullptr;
return false;
if (NS_WARN_IF(!val.isObject()))
return nullptr;
return false;
// The call to wrap() here is necessary even though the object is same-
// compartment, because it applies our security wrapper.
JS::RootedObject obj(cx, &val.toObject());
if (NS_WARN_IF(!JS_WrapObject(cx, &obj)))
return nullptr;
return obj;
obj.set(&val.toObject());
if (NS_WARN_IF(!JS_WrapObject(cx, obj)))
return false;
return true;
}
void
@ -174,8 +174,8 @@ XPCWrappedNativeScope::ForcePrivilegedComponents()
bool
XPCWrappedNativeScope::AttachComponentsObject(JSContext* aCx)
{
RootedObject components(aCx, GetComponentsJSObject());
if (!components)
RootedObject components(aCx);
if (!GetComponentsJSObject(&components))
return false;
RootedObject global(aCx, GetGlobalJSObject());
@ -697,7 +697,7 @@ XPCWrappedNativeScope::RemoveWrappedNativeProtos()
}
JSObject *
XPCWrappedNativeScope::GetExpandoChain(JSObject *target)
XPCWrappedNativeScope::GetExpandoChain(HandleObject target)
{
MOZ_ASSERT(GetObjectScope(target) == this);
if (!mXrayExpandos.initialized())

View File

@ -985,8 +985,8 @@ public:
bool AttachComponentsObject(JSContext *aCx);
// Returns the JS object reflection of the Components object.
JSObject*
GetComponentsJSObject();
bool
GetComponentsJSObject(JS::MutableHandleObject obj);
JSObject*
GetGlobalJSObject() const {
@ -1004,7 +1004,7 @@ public:
}
JSObject*
GetExpandoChain(JSObject *target);
GetExpandoChain(JS::HandleObject target);
bool
SetExpandoChain(JSContext *cx, JS::HandleObject target, JS::HandleObject chain);

View File

@ -208,7 +208,7 @@ public:
JSObject* ensureHolder(JSContext *cx, HandleObject wrapper);
virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper) = 0;
JSObject* getExpandoChain(JSObject *obj) {
JSObject* getExpandoChain(HandleObject obj) {
return GetObjectScope(obj)->GetExpandoChain(obj);
}

View File

@ -11,10 +11,12 @@
#include <pthread.h>
#include <SLES/OpenSLES.h>
#if defined(__ANDROID__)
#include <sys/system_properties.h>
#include "android/sles_definitions.h"
#include <SLES/OpenSLES_Android.h>
#include <android/log.h>
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Cubeb_OpenSL" , ## args)
#define ANDROID_VERSION_GINGERBREAD_MR1 10
#endif
#include "cubeb/cubeb.h"
#include "cubeb-internal.h"
@ -167,11 +169,38 @@ convert_stream_type_to_sl_stream(cubeb_stream_type stream_type)
static void opensl_destroy(cubeb * ctx);
#if defined(__ANDROID__)
static int
get_android_version(void)
{
char version_string[PROP_VALUE_MAX];
memset(version_string, 0, PROP_VALUE_MAX);
int len = __system_property_get("ro.build.version.sdk", version_string);
if (len <= 0) {
LOG("Failed to get Android version!\n");
return len;
}
return (int)strtol(version_string, NULL, 10);
}
#endif
/*static*/ int
opensl_init(cubeb ** context, char const * context_name)
{
cubeb * ctx;
#if defined(__ANDROID__)
int android_version = get_android_version();
if (android_version > 0 && android_version <= ANDROID_VERSION_GINGERBREAD_MR1) {
// Don't even attempt to run on Gingerbread and lower
return CUBEB_ERROR;
}
#endif
*context = NULL;
ctx = calloc(1, sizeof(*ctx));

View File

@ -2802,6 +2802,17 @@ int vcmGetVideoMaxSupportedPacketizationMode()
return 1;
}
/**
* Get supported H.264 profile-level-id
* @return supported profile-level-id value
*/
uint32_t vcmGetVideoH264ProfileLevelID()
{
// constrained baseline level 1.2
// XXX make variable based on openh264 and OMX support
return 0x42E00C;
}
/**
* MEDIA control received from far end on signaling path
*
@ -3043,62 +3054,6 @@ cc_boolean vcmCheckAttribs(cc_uint32_t media_type, void *sdp_p, int level, void
}
}
/**
* Add Video attributes in the offer/answer SDP
*
* This method is called for video codecs only. This method should populate the
* Video SDP attributes using the SDP helper API
*
* @param [in] sdp_p - opaque SDP pointer to be used via SDP helper APIs
* @param [in] level - Parameter to be used with SDP helper APIs
* @param [in] media_type - codec for which the SDP attributes are to be populated
* @param [in] payload_number - RTP payload type used for the SDP
* @param [in] isOffer - cc_boolean indicating we are encoding an offer or an aswer
*
* @return void
*/
void vcmPopulateAttribs(void *sdp_p, int level, cc_uint32_t media_type,
cc_uint16_t payload_number, cc_boolean isOffer)
{
CSFLogDebug( logTag, "vcmPopulateAttribs(): media=%d PT=%d, isOffer=%d", media_type, payload_number, isOffer);
uint16_t a_inst;//, a_inst2, a_inst3, a_inst4;
int profile;
char profile_level_id[MAX_SPROP_LEN];
switch (media_type)
{
case RTP_H264_P0:
case RTP_H264_P1:
if ( ccsdpAddNewAttr(sdp_p, level, 0, SDP_ATTR_FMTP, &a_inst) != SDP_SUCCESS ) return;
(void) ccsdpAttrSetFmtpPayloadType(sdp_p, level, 0, a_inst, payload_number);
if (media_type == RTP_H264_P1) {
(void) ccsdpAttrSetFmtpPackMode(sdp_p, level, 0, a_inst, 1 /*packetization_mode*/);
}
//(void) sdp_attr_set_fmtp_parameter_sets(sdp_p, level, 0, a_inst, "J0KAFJWgUH5A,KM4H8n=="); // NAL units 27 42 80 14 95 a0 50 7e 40 28 ce 07 f2
//profile = 0x42E000 + H264ToSDPLevel( vt_GetClientProfileLevel() );
profile = 0x42E00C;
csf_sprintf(profile_level_id, MAX_SPROP_LEN, "%X", profile);
(void) ccsdpAttrSetFmtpProfileLevelId(sdp_p, level, 0, a_inst, profile_level_id);
//(void) sdp_attr_set_fmtp_max_mbps(sdp_p, level, 0, a_inst, max_mbps);
//(void) sdp_attr_set_fmtp_max_fs(sdp_p, level, 0, a_inst, max_fs);
//(void) sdp_attr_set_fmtp_max_cpb(sdp_p, level, 0, a_inst, max_cpb);
//(void) sdp_attr_set_fmtp_max_dpb(sdp_p, level, 0, a_inst, max_dpb);
//(void) sdp_attr_set_fmtp_max_br(sdp_p, level, 0, a_inst, max_br);
//(void) sdp_add_new_bw_line(sdp_p, level, &a_inst);
//(void) sdp_set_bw(sdp_p, level, a_inst, SDP_BW_MODIFIER_TIAS, tias_bw);
break;
default:
break;
}
}
/**
* Send a DTMF digit
*

View File

@ -1137,6 +1137,7 @@ gsmsdp_set_video_media_attributes (uint32_t media_type, void *cc_sdp_p, uint16_t
uint16_t payload_number)
{
uint16_t a_inst;
int added_fmtp = 0;
void *sdp_p = ((cc_sdp_t*)cc_sdp_p)->src_sdp;
int max_fs = 0;
int max_fr = 0;
@ -1170,21 +1171,56 @@ gsmsdp_set_video_media_attributes (uint32_t media_type, void *cc_sdp_p, uint16_t
SIPSDP_ATTR_ENCNAME_H264);
(void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
RTPMAP_VIDEO_CLOCKRATE);
// we know we haven't added it yet
if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_FMTP, &a_inst)
!= SDP_SUCCESS) {
GSM_ERR_MSG("Failed to add attribute");
return;
}
added_fmtp = 1;
{
char buffer[32];
uint32_t profile_level_id = vcmGetVideoH264ProfileLevelID();
snprintf(buffer, sizeof(buffer), "0x%x", profile_level_id);
(void) sdp_attr_set_fmtp_profile_level_id(sdp_p, level, 0, a_inst,
buffer);
}
if (media_type == RTP_H264_P1) {
(void) sdp_attr_set_fmtp_pack_mode(sdp_p, level, 0, a_inst,
1);
}
// TODO: other parameters we may want/need to set for H.264
//(void) sdp_attr_set_fmtp_max_mbps(sdp_p, level, 0, a_inst, max_mbps);
//(void) sdp_attr_set_fmtp_max_fs(sdp_p, level, 0, a_inst, max_fs);
//(void) sdp_attr_set_fmtp_max_cpb(sdp_p, level, 0, a_inst, max_cpb);
//(void) sdp_attr_set_fmtp_max_dpb(sdp_p, level, 0, a_inst, max_dpb);
//(void) sdp_attr_set_fmtp_max_br(sdp_p, level, 0, a_inst, max_br);
//(void) sdp_add_new_bw_line(sdp_p, level, &a_inst);
//(void) sdp_set_bw(sdp_p, level, a_inst, SDP_BW_MODIFIER_TIAS, tias_bw);
break;
case RTP_VP8:
(void) sdp_attr_set_rtpmap_encname(sdp_p, level, 0, a_inst,
SIPSDP_ATTR_ENCNAME_VP8);
(void) sdp_attr_set_rtpmap_clockrate(sdp_p, level, 0, a_inst,
RTPMAP_VIDEO_CLOCKRATE);
break;
}
switch (media_type) {
case RTP_H264_P0:
case RTP_H264_P1:
case RTP_VP8:
max_fs = config_get_video_max_fs((rtp_ptype) media_type);
max_fr = config_get_video_max_fr((rtp_ptype) media_type);
if (max_fs || max_fr) {
if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_FMTP, &a_inst)
!= SDP_SUCCESS) {
GSM_ERR_MSG("Failed to add attribute");
return;
if (!added_fmtp) {
if (sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_FMTP, &a_inst)
!= SDP_SUCCESS) {
GSM_ERR_MSG("Failed to add attribute");
return;
}
added_fmtp = 1;
}
(void) sdp_attr_set_fmtp_payload_type(sdp_p, level, 0, a_inst,
@ -1200,13 +1236,8 @@ gsmsdp_set_video_media_attributes (uint32_t media_type, void *cc_sdp_p, uint16_t
max_fr);
}
}
break;
}
GSM_DEBUG("gsmsdp_set_video_media_attributes- populate attribs %d", payload_number );
vcmPopulateAttribs(cc_sdp_p, level, media_type, payload_number, FALSE);
break;
default:
@ -3430,7 +3461,7 @@ gsmsdp_negotiate_codec (fsmdef_dcb_t *dcb_p, cc_sdp_t *sdp_p,
audio_coding/main/source/acm_codec_database.cc */
payload_info->audio.frequency = 48000;
payload_info->audio.packet_size = 960;
payload_info->audio.bitrate = 32000;
payload_info->audio.bitrate = 16000; // Increase when we have higher capture rates
break;
case RTP_ISAC:

View File

@ -887,6 +887,12 @@ int vcmGetVideoCodecList(int request_type);
*/
int vcmGetVideoMaxSupportedPacketizationMode();
/**
* Get supported H.264 profile-level-id
* @return supported profile-level-id value
*/
uint32_t vcmGetVideoH264ProfileLevelID();
/**
* Get the rx/tx stream statistics associated with the call.
* The rx/tx stats are defined as comma seperated string as follows.

View File

@ -490,28 +490,6 @@ boolean vcmCheckAttribs(uint32_t media_type, void *sdp_p, int level, void **rcap
return TRUE;
}
/**
* Add Video attributes in the offer/answer SDP
*
* This method is called for video codecs only. This method should populate the
* Video SDP attributes using the SDP helper API
*
* @param [in] sdp_p - opaque SDP pointer to be used via SDP helper APIs
* @param [in] level - Parameter to be used with SDP helper APIs
* @param [in] media_type - codec for which the SDP attributes are to be populated
* @param [in] payload_number - RTP payload type used for the SDP
* @param [in] isOffer - boolean indicating we are encoding an offer or an aswer
*
* @return void
*/
void vcmPopulateAttribs(void *sdp_p, int level, uint32_t media_type,
uint16_t payload_number, boolean isOffer)
{
return;
}
/**
* Send a DTMF digit
*

View File

@ -7,6 +7,9 @@
# be found in the AUTHORS file in the root of the source tree.
{
'variables': {
'opus_complexity%': 0,
},
'targets': [
{
'target_name': 'webrtc_opus',
@ -26,6 +29,9 @@
'include_dirs': [
'<(webrtc_root)',
],
'defines': [
'OPUS_COMPLEXITY=<(opus_complexity)'
],
'sources': [
'interface/opus_interface.h',
'opus_interface.c',

View File

@ -103,6 +103,9 @@ int16_t WebRtcOpus_Encode(OpusEncInst* inst, int16_t* audio_in, int16_t samples,
int16_t WebRtcOpus_SetBitRate(OpusEncInst* inst, int32_t rate) {
if (inst) {
#if defined(OPUS_COMPLEXITY) && (OPUS_COMPLEXITY != 0)
opus_encoder_ctl(inst->encoder, OPUS_SET_COMPLEXITY(OPUS_COMPLEXITY));
#endif
return opus_encoder_ctl(inst->encoder, OPUS_SET_BITRATE(rate));
} else {
return -1;

View File

@ -40,6 +40,8 @@ skip-if = android_version == "10"
skip-if = processor == "x86"
[testFormHistory]
[testGetUserMedia]
# disabled on 2.3; see bug 981881]
skip-if = android_version == "10"
# [testHistory] # see bug 915350
[testHomeBanner]
# disabled on x86 only; bug 957185

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