mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c a=merge
This commit is contained in:
commit
426690253a
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
@ -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]
|
||||
|
@ -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 += [
|
||||
|
@ -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:
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
""",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -86,8 +86,6 @@ public:
|
||||
|
||||
DOMError* GetError(ErrorResult& aRv);
|
||||
|
||||
JSContext* GetJSContext();
|
||||
|
||||
void
|
||||
SetActor(IndexedDBRequestParentBase* aActorParent)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -39,7 +39,7 @@ interface TextTrack : EventTarget {
|
||||
[Throws]
|
||||
void removeCue(VTTCue cue);
|
||||
|
||||
attribute EventHandler oncuechange;
|
||||
//(Not implemented)attribute EventHandler oncuechange;
|
||||
};
|
||||
|
||||
// Mozilla Extensions
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 ========================================================
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
6
js/src/devtools/gctrace/Makefile
Normal file
6
js/src/devtools/gctrace/Makefile
Normal 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 $@ $<
|
765
js/src/devtools/gctrace/gcstats.cpp
Normal file
765
js/src/devtools/gctrace/gcstats.cpp
Normal 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;
|
||||
}
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
195
js/src/gc/GCTrace.cpp
Normal 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
53
js/src/gc/GCTrace.h
Normal 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
54
js/src/gc/GCTraceFormat.h
Normal 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
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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, ¶mName,
|
||||
bytes, strlen(bytes), options));
|
||||
CHECK(JS_CompileFunction(cx, global, "trusted", 1, ¶mName,
|
||||
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, ¶mName,
|
||||
bytes, strlen(bytes), options));
|
||||
CHECK(JS_CompileFunction(cx, global, "untrusted", 1, ¶mName,
|
||||
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, ¶mName,
|
||||
bytes, strlen(bytes), options));
|
||||
CHECK(JS_CompileFunction(cx, global, "trusted", 1, ¶mName,
|
||||
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, ¶mName,
|
||||
bytes, strlen(bytes), options));
|
||||
CHECK(JS_CompileFunction(cx, global, "untrusted", 1, ¶mName,
|
||||
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, ¶mName,
|
||||
bytes, strlen(bytes), options));
|
||||
CHECK(JS_CompileFunction(cx, global, "untrusted", 1, ¶mName,
|
||||
bytes, strlen(bytes), options, &fun));
|
||||
|
||||
JS::RootedValue arg(cx, JS::ObjectValue(*callTrusted));
|
||||
JS::RootedValue rval(cx);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
220
js/src/jsapi.cpp
220
js/src/jsapi.cpp
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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>();
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user