This commit is contained in:
Ryan VanderMeulen 2014-12-05 19:02:53 -05:00
Родитель be495d3934 e17b14bb50
Коммит 5f0aa6245d
49 изменённых файлов: 1350 добавлений и 254 удалений

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

@ -86,7 +86,7 @@ var NewPrefDialog = {
}
// If item already in list, it's being changed, else added
let item = document.querySelector(".pref-item[name=" + aPrefName.quote() + "]");
let item = document.querySelector(".pref-item[name=\"" + CSS.escape(aPrefName) + "\"]");
if (item) {
this._positiveButton.textContent = gStringBundle.GetStringFromName("newPref.changeButton");
} else {
@ -463,7 +463,7 @@ var AboutConfig = {
}
// If pref not already in list, refresh display as it's being added
let item = document.querySelector(".pref-item[name=" + pref.name.quote() + "]");
let item = document.querySelector(".pref-item[name=\"" + CSS.escape(pref.name) + "\"]");
if (!item) {
document.location.reload();
return;

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

@ -1103,7 +1103,10 @@ HTMLImageElement::TryCreateResponsiveSelector(nsIContent *aSourceNode,
nsAutoString type;
if (aSourceNode->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type) &&
!imgLoader::SupportImageWithMimeType(NS_ConvertUTF16toUTF8(type).get())) {
!imgLoader::SupportImageWithMimeType(
NS_ConvertUTF16toUTF8(type).get(),
AcceptedMimeTypes::IMAGES_AND_DOCUMENTS)
) {
return false;
}
} else if (aSourceNode->Tag() == nsGkAtoms::img) {

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

@ -0,0 +1,11 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<body>
<picture>
<source srcset="lime100x100.svg" type="image/svg+xml">
<img src="red.png" width="100" height="100">
</picture>
</body>
</html>

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

@ -0,0 +1,11 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<body>
<picture>
<source srcset="lime100x100.svg">
<img src="red.png" width="100" height="100">
</picture>
</body>
</html>

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

@ -0,0 +1,8 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<body>
<img src="lime100x100.svg">
</body>
</html>

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

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="100" height="100">
<rect width="100%" height="100%" fill="lime"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 141 B

Двоичные данные
dom/html/reftests/red.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 82 B

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

@ -41,6 +41,10 @@ skip-if(Android||B2G) == 649134-2.html 649134-2-ref.html
fuzzy(1,149) == bug917595-iframe-1.html bug917595-1-ref.html
skip-if(B2G) fuzzy-if(!B2G,3,640) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
# Test support for SVG-as-image in <picture> elements.
pref(dom.image.picture.enabled,true) pref(dom.image.srcset.enabled,true) == bug1106522-1.html bug1106522-ref.html
pref(dom.image.picture.enabled,true) pref(dom.image.srcset.enabled,true) == bug1106522-2.html bug1106522-ref.html
== href-attr-change-restyles.html href-attr-change-restyles-ref.html
== figure.html figure-ref.html
== pre-1.html pre-1-ref.html

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

@ -25,7 +25,7 @@
using mozilla::dom::CrashReporterChild;
static const int MAX_PLUGIN_VOUCHER_LENGTH = 500000;
static const int MAX_VOUCHER_LENGTH = 500000;
#ifdef XP_WIN
#include <stdlib.h> // for _exit()
@ -255,6 +255,7 @@ GMPChild::CheckThread()
bool
GMPChild::Init(const std::string& aPluginPath,
const std::string& aVoucherPath,
base::ProcessHandle aParentProcessHandle,
MessageLoop* aIOLoop,
IPC::Channel* aChannel)
@ -268,6 +269,7 @@ GMPChild::Init(const std::string& aPluginPath,
#endif
mPluginPath = aPluginPath;
mVoucherPath = aVoucherPath;
return true;
}
@ -398,6 +400,7 @@ GMPChild::RecvStartPlugin()
PreLoadLibraries(mPluginPath);
#endif
PreLoadPluginVoucher(mPluginPath);
PreLoadSandboxVoucher();
nsCString libPath;
if (!GetLibPath(libPath)) {
@ -523,7 +526,7 @@ GMPChild::DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor)
PGMPDecryptorChild*
GMPChild::AllocPGMPDecryptorChild()
{
GMPDecryptorChild* actor = new GMPDecryptorChild(this, mPluginVoucher);
GMPDecryptorChild* actor = new GMPDecryptorChild(this, mPluginVoucher, mSandboxVoucher);
actor->AddRef();
return actor;
}
@ -730,7 +733,7 @@ GMPChild::PreLoadPluginVoucher(const std::string& aPluginPath)
std::streampos end = stream.tellg();
stream.seekg (0, std::ios::beg);
auto length = end - start;
if (length > MAX_PLUGIN_VOUCHER_LENGTH) {
if (length > MAX_VOUCHER_LENGTH) {
NS_WARNING("Plugin voucher file too big!");
return false;
}
@ -745,5 +748,33 @@ GMPChild::PreLoadPluginVoucher(const std::string& aPluginPath)
return true;
}
void
GMPChild::PreLoadSandboxVoucher()
{
std::ifstream stream;
stream.open(mVoucherPath.c_str(), std::ios::binary);
if (!stream.good()) {
NS_WARNING("PreLoadSandboxVoucher can't find sandbox voucher file!");
return;
}
std::streampos start = stream.tellg();
stream.seekg (0, std::ios::end);
std::streampos end = stream.tellg();
stream.seekg (0, std::ios::beg);
auto length = end - start;
if (length > MAX_VOUCHER_LENGTH) {
NS_WARNING("PreLoadSandboxVoucher sandbox voucher file too big!");
return;
}
mSandboxVoucher.SetLength(length);
stream.read((char*)mSandboxVoucher.Elements(), length);
if (!stream) {
NS_WARNING("PreLoadSandboxVoucher failed to read plugin voucher file!");
return;
}
}
} // namespace gmp
} // namespace mozilla

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

@ -27,6 +27,7 @@ public:
virtual ~GMPChild();
bool Init(const std::string& aPluginPath,
const std::string& aVoucherPath,
base::ProcessHandle aParentProcessHandle,
MessageLoop* aIOLoop,
IPC::Channel* aChannel);
@ -52,6 +53,7 @@ public:
private:
bool PreLoadPluginVoucher(const std::string& aPluginPath);
void PreLoadSandboxVoucher();
bool GetLibPath(nsACString& aOutLibPath);
@ -97,12 +99,14 @@ private:
MessageLoop* mGMPMessageLoop;
std::string mPluginPath;
std::string mVoucherPath;
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
nsCString mPluginBinaryPath;
#endif
std::string mNodeId;
GMPLoader* mGMPLoader;
nsTArray<uint8_t> mPluginVoucher;
nsTArray<uint8_t> mSandboxVoucher;
};
} // namespace gmp

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

@ -27,10 +27,12 @@ namespace mozilla {
namespace gmp {
GMPDecryptorChild::GMPDecryptorChild(GMPChild* aPlugin,
const nsTArray<uint8_t>& aPluginVoucher)
const nsTArray<uint8_t>& aPluginVoucher,
const nsTArray<uint8_t>& aSandboxVoucher)
: mSession(nullptr)
, mPlugin(aPlugin)
, mPluginVoucher(aPluginVoucher)
, mSandboxVoucher(aSandboxVoucher)
{
MOZ_ASSERT(mPlugin);
}
@ -181,9 +183,8 @@ GMPDecryptorChild::GetSandboxVoucher(const uint8_t** aVoucher,
if (!aVoucher || !aVoucherLength) {
return;
}
const char* voucher = "placeholder_sandbox_voucher.";
*aVoucher = (uint8_t*)voucher;
*aVoucherLength = strlen(voucher);
*aVoucher = mSandboxVoucher.Elements();
*aVoucherLength = mSandboxVoucher.Length();
}
void

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

@ -25,7 +25,8 @@ public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPDecryptorChild);
explicit GMPDecryptorChild(GMPChild* aPlugin,
const nsTArray<uint8_t>& aPluginVoucher);
const nsTArray<uint8_t>& aPluginVoucher,
const nsTArray<uint8_t>& aSandboxVoucher);
void Init(GMPDecryptor* aSession);
@ -122,8 +123,9 @@ private:
GMPDecryptor* mSession;
GMPChild* mPlugin;
// Reference to the voucher owned by the GMPChild.
// Reference to the vouchers owned by the GMPChild.
const nsTArray<uint8_t>& mPluginVoucher;
const nsTArray<uint8_t>& mSandboxVoucher;
};
} // namespace gmp

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

@ -29,18 +29,21 @@ bool
GMPProcessChild::Init()
{
std::string pluginFilename;
std::string voucherFilename;
#if defined(OS_POSIX)
// NB: need to be very careful in ensuring that the first arg
// (after the binary name) here is indeed the plugin module path.
// Keep in sync with dom/plugins/PluginModuleParent.
std::vector<std::string> values = CommandLine::ForCurrentProcess()->argv();
NS_ABORT_IF_FALSE(values.size() >= 2, "not enough args");
NS_ABORT_IF_FALSE(values.size() >= 3, "not enough args");
pluginFilename = values[1];
voucherFilename = values[2];
#elif defined(OS_WIN)
std::vector<std::wstring> values = CommandLine::ForCurrentProcess()->GetLooseValues();
NS_ABORT_IF_FALSE(values.size() >= 1, "not enough loose args");
NS_ABORT_IF_FALSE(values.size() >= 2, "not enough loose args");
pluginFilename = WideToUTF8(values[0]);
voucherFilename = WideToUTF8(values[1]);
#else
#error Not implemented
#endif
@ -48,6 +51,7 @@ GMPProcessChild::Init()
BackgroundHangMonitor::Startup();
return mPlugin.Init(pluginFilename,
voucherFilename,
ParentHandle(),
IOThreadChild::message_loop(),
IOThreadChild::channel());

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

@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPProcessParent.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIFile.h"
#include "base/string_util.h"
#include "base/process_util.h"
@ -43,8 +45,19 @@ GMPProcessParent::~GMPProcessParent()
bool
GMPProcessParent::Launch(int32_t aTimeoutMs)
{
nsCOMPtr<nsIFile> greDir;
NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greDir));
if (!greDir) {
NS_WARNING("GMPProcessParent can't get NS_GRE_DIR");
return false;
}
greDir->AppendNative(NS_LITERAL_CSTRING("voucher.bin"));
nsAutoCString voucherPath;
greDir->GetNativePath(voucherPath);
vector<string> args;
args.push_back(mGMPPath);
args.push_back(string(voucherPath.BeginReading(), voucherPath.EndReading()));
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
std::wstring wGMPPath = UTF8ToWide(mGMPPath.c_str());

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

@ -2728,6 +2728,9 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
bool scrollOffsetUpdated = aLayerMetrics.GetScrollOffsetUpdated()
&& (aLayerMetrics.GetScrollGeneration() != mFrameMetrics.GetScrollGeneration());
bool smoothScrollRequested = aLayerMetrics.GetDoSmoothScroll()
&& (aLayerMetrics.GetScrollGeneration() != mFrameMetrics.GetScrollGeneration());
if (aIsFirstPaint || isDefault) {
// Initialize our internal state to something sane when the content
// that was just painted is something we knew nothing about previously
@ -2749,9 +2752,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
needContentRepaint = true;
}
} else {
bool smoothScrollRequested = aLayerMetrics.GetDoSmoothScroll()
&& (aLayerMetrics.GetScrollGeneration() != mFrameMetrics.GetScrollGeneration());
// If we're not taking the aLayerMetrics wholesale we still need to pull
// in some things into our local mFrameMetrics because these things are
// determined by Gecko and our copy in mFrameMetrics may be stale.
@ -2805,23 +2805,23 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
// last thing we know was painted by Gecko.
mLastDispatchedPaintMetrics = aLayerMetrics;
}
}
if (smoothScrollRequested) {
// A smooth scroll has been requested for animation on the compositor
// thread. This flag will be reset by the main thread when it receives
// the scroll update acknowledgement.
if (smoothScrollRequested) {
// A smooth scroll has been requested for animation on the compositor
// thread. This flag will be reset by the main thread when it receives
// the scroll update acknowledgement.
APZC_LOG("%p smooth scrolling from %s to %s\n", this,
Stringify(mFrameMetrics.GetScrollOffset()).c_str(),
Stringify(aLayerMetrics.GetSmoothScrollOffset()).c_str());
APZC_LOG("%p smooth scrolling from %s to %s\n", this,
Stringify(mFrameMetrics.GetScrollOffset()).c_str(),
Stringify(aLayerMetrics.GetSmoothScrollOffset()).c_str());
mFrameMetrics.CopySmoothScrollInfoFrom(aLayerMetrics);
CancelAnimation();
mLastDispatchedPaintMetrics = aLayerMetrics;
StartSmoothScroll();
mFrameMetrics.CopySmoothScrollInfoFrom(aLayerMetrics);
CancelAnimation();
mLastDispatchedPaintMetrics = aLayerMetrics;
StartSmoothScroll();
scrollOffsetUpdated = true; // Ensure that AcknowledgeScrollUpdate is called
}
scrollOffsetUpdated = true; // Ensure that AcknowledgeScrollUpdate is called
}
if (scrollOffsetUpdated) {

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

@ -2304,10 +2304,19 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel *channel, imgINotificationOb
return rv;
}
bool imgLoader::SupportImageWithMimeType(const char* aMimeType)
bool
imgLoader::SupportImageWithMimeType(const char* aMimeType,
AcceptedMimeTypes aAccept
/* = AcceptedMimeTypes::IMAGES */)
{
nsAutoCString mimeType(aMimeType);
ToLowerCase(mimeType);
if (aAccept == AcceptedMimeTypes::IMAGES_AND_DOCUMENTS &&
mimeType.EqualsLiteral("image/svg+xml")) {
return true;
}
return Image::GetDecoderType(mimeType.get()) != Image::eDecoderType_unknown;
}

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

@ -206,6 +206,11 @@ private:
uint32_t mSize;
};
MOZ_BEGIN_ENUM_CLASS(AcceptedMimeTypes, uint8_t)
IMAGES,
IMAGES_AND_DOCUMENTS,
MOZ_END_ENUM_CLASS(AcceptedMimeTypes)
class imgLoader MOZ_FINAL : public imgILoader,
public nsIContentSniffer,
public imgICache,
@ -271,8 +276,22 @@ public:
imgRequestProxy **_retval);
static nsresult GetMimeTypeFromContent(const char* aContents, uint32_t aLength, nsACString& aContentType);
// exported for use by mimei.cpp in libxul sdk builds
static NS_EXPORT_(bool) SupportImageWithMimeType(const char* aMimeType);
/**
* Returns true if the given mime type may be interpreted as an image.
*
* Some MIME types may be interpreted as both images and documents. (At the
* moment only "image/svg+xml" falls into this category, but there may be more
* in the future.) Callers which want this function to return true for such
* MIME types should pass AcceptedMimeTypes::IMAGES_AND_DOCUMENTS for @aAccept.
*
* @param aMimeType The MIME type to evaluate.
* @param aAcceptedMimeTypes Which kinds of MIME types to treat as images.
*/
static NS_EXPORT_(bool)
SupportImageWithMimeType(const char* aMimeType,
AcceptedMimeTypes aAccept =
AcceptedMimeTypes::IMAGES);
static void GlobalInit(); // for use by the factory
static void Shutdown(); // for use by the factory

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

@ -19,6 +19,7 @@
#include "jsobjinlines.h"
#include "vm/Interpreter-inl.h"
#include "vm/NativeObject-inl.h"
using namespace js;
@ -1237,11 +1238,24 @@ MapObject::construct(JSContext *cx, unsigned argc, Value *vp)
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.get(0).isNullOrUndefined()) {
RootedValue adderVal(cx);
if (!JSObject::getProperty(cx, obj, obj, cx->names().set, &adderVal))
return false;
if (!IsCallable(adderVal))
return ReportIsNotFunction(cx, adderVal);
bool isOriginalAdder = IsNativeFunction(adderVal, MapObject::set);
RootedValue mapVal(cx, ObjectValue(*obj));
FastInvokeGuard fig(cx, adderVal);
InvokeArgs &args2 = fig.args();
ForOfIterator iter(cx);
if (!iter.init(args[0]))
return false;
RootedValue pairVal(cx);
RootedObject pairObj(cx);
AutoHashableValueRooter hkey(cx);
ValueMap *map = obj->getData();
while (true) {
bool done;
@ -1263,20 +1277,32 @@ MapObject::construct(JSContext *cx, unsigned argc, Value *vp)
if (!JSObject::getElement(cx, pairObj, pairObj, 0, &key))
return false;
AutoHashableValueRooter hkey(cx);
if (!hkey.setValue(cx, key))
return false;
RootedValue val(cx);
if (!JSObject::getElement(cx, pairObj, pairObj, 1, &val))
return false;
RelocatableValue rval(val);
if (!map->put(hkey, rval)) {
js_ReportOutOfMemory(cx);
return false;
if (isOriginalAdder) {
if (!hkey.setValue(cx, key))
return false;
RelocatableValue rval(val);
if (!map->put(hkey, rval)) {
js_ReportOutOfMemory(cx);
return false;
}
WriteBarrierPost(cx->runtime(), map, key);
} else {
if (!args2.init(2))
return false;
args2.setCallee(adderVal);
args2.setThis(mapVal);
args2[0].set(key);
args2[1].set(val);
if (!fig.invoke(cx))
return false;
}
WriteBarrierPost(cx->runtime(), map, key);
}
}
@ -1801,6 +1827,18 @@ SetObject::construct(JSContext *cx, unsigned argc, Value *vp)
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.get(0).isNullOrUndefined()) {
RootedValue adderVal(cx);
if (!JSObject::getProperty(cx, obj, obj, cx->names().add, &adderVal))
return false;
if (!IsCallable(adderVal))
return ReportIsNotFunction(cx, adderVal);
bool isOriginalAdder = IsNativeFunction(adderVal, SetObject::add);
RootedValue setVal(cx, ObjectValue(*obj));
FastInvokeGuard fig(cx, adderVal);
InvokeArgs &args2 = fig.args();
RootedValue keyVal(cx);
ForOfIterator iter(cx);
if (!iter.init(args[0]))
@ -1813,13 +1851,26 @@ SetObject::construct(JSContext *cx, unsigned argc, Value *vp)
return false;
if (done)
break;
if (!key.setValue(cx, keyVal))
return false;
if (!set->put(key)) {
js_ReportOutOfMemory(cx);
return false;
if (isOriginalAdder) {
if (!key.setValue(cx, keyVal))
return false;
if (!set->put(key)) {
js_ReportOutOfMemory(cx);
return false;
}
WriteBarrierPost(cx->runtime(), set, keyVal);
} else {
if (!args2.init(1))
return false;
args2.setCallee(adderVal);
args2.setThis(setVal);
args2[0].set(keyVal);
if (!fig.invoke(cx))
return false;
}
WriteBarrierPost(cx->runtime(), set, keyVal);
}
}

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

@ -12,9 +12,11 @@
#include "builtin/SelfHostingDefines.h"
#include "vm/GlobalObject.h"
#include "vm/SelfHosting.h"
#include "jsobjinlines.h"
#include "vm/Interpreter-inl.h"
#include "vm/NativeObject-inl.h"
using namespace js;
@ -98,6 +100,20 @@ WeakSetObject::construct(JSContext *cx, unsigned argc, Value *vp)
if (!args.get(0).isNullOrUndefined()) {
RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject());
RootedValue adderVal(cx);
if (!JSObject::getProperty(cx, obj, obj, cx->names().add, &adderVal))
return false;
if (!IsCallable(adderVal))
return ReportIsNotFunction(cx, adderVal);
JSFunction *adder;
bool isOriginalAdder = IsFunctionObject(adderVal, &adder) &&
IsSelfHostedFunctionWithName(adder, cx->names().WeakSet_add);
RootedValue setVal(cx, ObjectValue(*obj));
FastInvokeGuard fig(cx, adderVal);
InvokeArgs &args2 = fig.args();
JS::ForOfIterator iter(cx);
if (!iter.init(args[0]))
return false;
@ -112,14 +128,26 @@ WeakSetObject::construct(JSContext *cx, unsigned argc, Value *vp)
if (done)
break;
if (keyVal.isPrimitive()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
return false;
}
if (isOriginalAdder) {
if (keyVal.isPrimitive()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
return false;
}
keyObject = &keyVal.toObject();
if (!SetWeakMapEntry(cx, map, keyObject, placeholder))
return false;
keyObject = &keyVal.toObject();
if (!SetWeakMapEntry(cx, map, keyObject, placeholder))
return false;
} else {
if (!args2.init(1))
return false;
args2.setCallee(adderVal);
args2.setThis(setVal);
args2[0].set(keyVal);
if (!fig.invoke(cx))
return false;
}
}
}

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

@ -0,0 +1,204 @@
load(libdir + "asserts.js");
load(libdir + "iteration.js");
var k1 = {};
var v1 = 42;
var k2 = {};
var v2 = 42;
var k3 = {};
var v3 = 43;
var k4 = {};
var v4 = 44;
function test_patched() {
let orig = Map.prototype.set;
// If adder is modified, constructor should call it.
var called = false;
Map.prototype.set = function(k, v) {
assertEq(k, k1);
assertEq(v, v1);
orig.call(this, k2, v2);
called = true;
};
var arr = [[k1, v1]];
var m = new Map(arr);
assertEq(called, true);
assertEq(m.size, 1);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
assertEq(m.get(k1), undefined);
assertEq(m.get(k2), v2);
Map.prototype.set = orig;
}
function test_proxy1() {
let orig = Map.prototype.set;
// If adder is modified, constructor should call it.
var called = false;
Map.prototype.set = new Proxy(function(k, v) {
assertEq(k, k1);
assertEq(v, v1);
orig.call(this, k2, v2);
called = true;
}, {});
var arr = [[k1, v1]];
var m = new Map(arr);
assertEq(called, true);
assertEq(m.size, 1);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
assertEq(m.get(k1), undefined);
assertEq(m.get(k2), v2);
Map.prototype.set = orig;
}
function test_proxy2() {
let orig = Map.prototype.set;
// If adder is modified, constructor should call it.
var called = false;
Map.prototype.set = new Proxy(function() {
}, {
apply: function(target, that, args) {
var [k, v] = args;
assertEq(k, k1);
assertEq(v, v1);
orig.call(that, k2, v2);
called = true;
}
});
var arr = [[k1, v1]];
var m = new Map(arr);
assertEq(called, true);
assertEq(m.size, 1);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
assertEq(m.get(k1), undefined);
assertEq(m.get(k2), v2);
Map.prototype.set = orig;
}
function test_change1() {
let orig = Map.prototype.set;
// Change to adder in GetIterator(..) call should be ignored.
var called = false;
var modified = false;
var arr = [[k1, v1]];
var proxy_arr = new Proxy(arr, {
get: function(target, name) {
if (name == std_iterator) {
modified = true;
Map.prototype.set = function() {
called = true;
};
}
return target[name];
}
});
var m = new Map(proxy_arr);
assertEq(modified, true);
assertEq(called, false);
assertEq(m.size, 1);
assertEq(m.has(k1), true);
assertEq(m.has(k2), false);
assertEq(m.get(k1), v1);
assertEq(m.get(k2), undefined);
Map.prototype.set = orig;
}
function test_change2() {
let orig = Map.prototype.set;
// Change to adder in adder(...) call should be ignored.
var called = false;
var count = 0;
Map.prototype.set = function(k, v) {
if (count == 0) {
assertEq(k, k1);
assertEq(v, v1);
orig.call(this, k3, v3);
Map.prototype.set = function() {
called = true;
};
count = 1;
} else {
assertEq(k, k2);
assertEq(v, v2);
orig.call(this, k4, v4);
count = 2;
}
};
var arr = [[k1, v1], [k2, v2]];
var m = new Map(arr);
assertEq(called, false);
assertEq(count, 2);
assertEq(m.size, 2);
assertEq(m.has(k1), false);
assertEq(m.has(k2), false);
assertEq(m.has(k3), true);
assertEq(m.has(k4), true);
assertEq(m.get(k1), undefined);
assertEq(m.get(k2), undefined);
assertEq(m.get(k3), v3);
assertEq(m.get(k4), v4);
Map.prototype.set = orig;
}
function test_error() {
let orig = Map.prototype.set;
var arr = [[k1, v1]];
// Map should throw TypeError if adder is not callable.
Map.prototype.set = null;
assertThrowsInstanceOf(() => new Map(arr), TypeError);
Map.prototype.set = {};
assertThrowsInstanceOf(() => new Map(arr), TypeError);
// Map should propagate error thrown by adder.
Map.prototype.set = function() {
throw SyntaxError();
};
assertThrowsInstanceOf(() => new Map(arr), SyntaxError);
Map.prototype.set = orig;
}
function test() {
test_patched();
test_proxy1();
test_proxy2();
test_change1();
test_change2();
test_error();
}
test();

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

@ -0,0 +1,183 @@
load(libdir + "asserts.js");
load(libdir + "iteration.js");
var k1 = {};
var k2 = {};
var k3 = {};
var k4 = {};
function test_patched() {
let orig = Set.prototype.add;
// If adder is modified, constructor should call it.
var called = false;
Set.prototype.add = function(k, v) {
assertEq(k, k1);
orig.call(this, k2);
called = true;
};
var arr = [k1];
var m = new Set(arr);
assertEq(called, true);
assertEq(m.size, 1);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
Set.prototype.add = orig;
}
function test_proxy1() {
let orig = Set.prototype.add;
// If adder is modified, constructor should call it.
var called = false;
Set.prototype.add = new Proxy(function(k, v) {
assertEq(k, k1);
orig.call(this, k2);
called = true;
}, {});
var arr = [k1];
var m = new Set(arr);
assertEq(called, true);
assertEq(m.size, 1);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
Set.prototype.add = orig;
}
function test_proxy2() {
let orig = Set.prototype.add;
// If adder is modified, constructor should call it.
var called = false;
Set.prototype.add = new Proxy(function() {
}, {
apply: function(target, that, args) {
var [k, v] = args;
assertEq(k, k1);
orig.call(that, k2);
called = true;
}
});
var arr = [k1];
var m = new Set(arr);
assertEq(called, true);
assertEq(m.size, 1);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
Set.prototype.add = orig;
}
function test_change1() {
let orig = Set.prototype.add;
// Change to adder in GetIterator(..) call should be ignored.
var called = false;
var modified = false;
var arr = [k1];
var proxy_arr = new Proxy(arr, {
get: function(target, name) {
if (name == std_iterator) {
modified = true;
Set.prototype.add = function() {
called = true;
};
}
return target[name];
}
});
var m = new Set(proxy_arr);
assertEq(modified, true);
assertEq(called, false);
assertEq(m.size, 1);
assertEq(m.has(k1), true);
assertEq(m.has(k2), false);
Set.prototype.add = orig;
}
function test_change2() {
let orig = Set.prototype.add;
// Change to adder in adder(...) call should be ignored.
var called = false;
var count = 0;
Set.prototype.add = function(k, v) {
if (count == 0) {
assertEq(k, k1);
orig.call(this, k3);
Set.prototype.add = function() {
called = true;
};
count = 1;
} else {
assertEq(k, k2);
orig.call(this, k4);
count = 2;
}
};
var arr = [k1, k2];
var m = new Set(arr);
assertEq(called, false);
assertEq(count, 2);
assertEq(m.size, 2);
assertEq(m.has(k1), false);
assertEq(m.has(k2), false);
assertEq(m.has(k3), true);
assertEq(m.has(k4), true);
Set.prototype.add = orig;
}
function test_error() {
let orig = Set.prototype.add;
var arr = [k1];
// Set should throw TypeError if adder is not callable.
Set.prototype.add = null;
assertThrowsInstanceOf(() => new Set(arr), TypeError);
Set.prototype.add = {};
assertThrowsInstanceOf(() => new Set(arr), TypeError);
// Set should propagate error thrown by adder.
Set.prototype.add = function() {
throw SyntaxError();
};
assertThrowsInstanceOf(() => new Set(arr), SyntaxError);
Set.prototype.add = orig;
}
function test() {
test_patched();
test_proxy1();
test_proxy2();
test_change1();
test_change2();
test_error();
}
test();

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

@ -0,0 +1,199 @@
load(libdir + "asserts.js");
load(libdir + "iteration.js");
var k1 = {};
var v1 = 42;
var k2 = {};
var v2 = 42;
var k3 = {};
var v3 = 43;
var k4 = {};
var v4 = 44;
function test_patched() {
let orig = WeakMap.prototype.set;
// If adder is modified, constructor should call it.
var called = false;
WeakMap.prototype.set = function(k, v) {
assertEq(k, k1);
assertEq(v, v1);
orig.call(this, k2, v2);
called = true;
};
var arr = [[k1, v1]];
var m = new WeakMap(arr);
assertEq(called, true);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
assertEq(m.get(k1), undefined);
assertEq(m.get(k2), v2);
WeakMap.prototype.set = orig;
}
function test_proxy1() {
let orig = WeakMap.prototype.set;
// If adder is modified, constructor should call it.
var called = false;
WeakMap.prototype.set = new Proxy(function(k, v) {
assertEq(k, k1);
assertEq(v, v1);
orig.call(this, k2, v2);
called = true;
}, {});
var arr = [[k1, v1]];
var m = new WeakMap(arr);
assertEq(called, true);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
assertEq(m.get(k1), undefined);
assertEq(m.get(k2), v2);
WeakMap.prototype.set = orig;
}
function test_proxy2() {
let orig = WeakMap.prototype.set;
// If adder is modified, constructor should call it.
var called = false;
WeakMap.prototype.set = new Proxy(function() {
}, {
apply: function(target, that, args) {
var [k, v] = args;
assertEq(k, k1);
assertEq(v, v1);
orig.call(that, k2, v2);
called = true;
}
});
var arr = [[k1, v1]];
var m = new WeakMap(arr);
assertEq(called, true);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
assertEq(m.get(k1), undefined);
assertEq(m.get(k2), v2);
WeakMap.prototype.set = orig;
}
function test_change1() {
let orig = WeakMap.prototype.set;
// Change to adder in GetIterator(..) call should be ignored.
var called = false;
var modified = false;
var arr = [[k1, v1]];
var proxy_arr = new Proxy(arr, {
get: function(target, name) {
if (name == std_iterator) {
modified = true;
WeakMap.prototype.set = function() {
called = true;
};
}
return target[name];
}
});
var m = new WeakMap(proxy_arr);
assertEq(modified, true);
assertEq(called, false);
assertEq(m.has(k1), true);
assertEq(m.has(k2), false);
assertEq(m.get(k1), v1);
assertEq(m.get(k2), undefined);
WeakMap.prototype.set = orig;
}
function test_change2() {
let orig = WeakMap.prototype.set;
// Change to adder in adder(...) call should be ignored.
var called = false;
var count = 0;
WeakMap.prototype.set = function(k, v) {
if (count == 0) {
assertEq(k, k1);
assertEq(v, v1);
orig.call(this, k3, v3);
WeakMap.prototype.set = function() {
called = true;
};
count = 1;
} else {
assertEq(k, k2);
assertEq(v, v2);
orig.call(this, k4, v4);
count = 2;
}
};
var arr = [[k1, v1], [k2, v2]];
var m = new WeakMap(arr);
assertEq(called, false);
assertEq(count, 2);
assertEq(m.has(k1), false);
assertEq(m.has(k2), false);
assertEq(m.has(k3), true);
assertEq(m.has(k4), true);
assertEq(m.get(k1), undefined);
assertEq(m.get(k2), undefined);
assertEq(m.get(k3), v3);
assertEq(m.get(k4), v4);
WeakMap.prototype.set = orig;
}
function test_error() {
let orig = WeakMap.prototype.set;
var arr = [[k1, v1]];
// WeakMap should throw TypeError if adder is not callable.
WeakMap.prototype.set = null;
assertThrowsInstanceOf(() => new WeakMap(arr), TypeError);
WeakMap.prototype.set = {};
assertThrowsInstanceOf(() => new WeakMap(arr), TypeError);
// WeakMap should propagate error thrown by adder.
WeakMap.prototype.set = function() {
throw SyntaxError();
};
assertThrowsInstanceOf(() => new WeakMap(arr), SyntaxError);
WeakMap.prototype.set = orig;
}
function test() {
test_patched();
test_proxy1();
test_proxy2();
test_change1();
test_change2();
test_error();
}
test();

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

@ -0,0 +1,178 @@
load(libdir + "asserts.js");
load(libdir + "iteration.js");
var k1 = {};
var k2 = {};
var k3 = {};
var k4 = {};
function test_patched() {
let orig = WeakSet.prototype.add;
// If adder is modified, constructor should call it.
var called = false;
WeakSet.prototype.add = function(k, v) {
assertEq(k, k1);
orig.call(this, k2);
called = true;
};
var arr = [k1];
var m = new WeakSet(arr);
assertEq(called, true);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
WeakSet.prototype.add = orig;
}
function test_proxy1() {
let orig = WeakSet.prototype.add;
// If adder is modified, constructor should call it.
var called = false;
WeakSet.prototype.add = new Proxy(function(k, v) {
assertEq(k, k1);
orig.call(this, k2);
called = true;
}, {});
var arr = [k1];
var m = new WeakSet(arr);
assertEq(called, true);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
WeakSet.prototype.add = orig;
}
function test_proxy2() {
let orig = WeakSet.prototype.add;
// If adder is modified, constructor should call it.
var called = false;
WeakSet.prototype.add = new Proxy(function() {
}, {
apply: function(target, that, args) {
var [k, v] = args;
assertEq(k, k1);
orig.call(that, k2);
called = true;
}
});
var arr = [k1];
var m = new WeakSet(arr);
assertEq(called, true);
assertEq(m.has(k1), false);
assertEq(m.has(k2), true);
WeakSet.prototype.add = orig;
}
function test_change1() {
let orig = WeakSet.prototype.add;
// Change to adder in GetIterator(..) call should be ignored.
var called = false;
var modified = false;
var arr = [k1];
var proxy_arr = new Proxy(arr, {
get: function(target, name) {
if (name == std_iterator) {
modified = true;
WeakSet.prototype.add = function() {
called = true;
};
}
return target[name];
}
});
var m = new WeakSet(proxy_arr);
assertEq(modified, true);
assertEq(called, false);
assertEq(m.has(k1), true);
assertEq(m.has(k2), false);
WeakSet.prototype.add = orig;
}
function test_change2() {
let orig = WeakSet.prototype.add;
// Change to adder in adder(...) call should be ignored.
var called = false;
var count = 0;
WeakSet.prototype.add = function(k, v) {
if (count == 0) {
assertEq(k, k1);
orig.call(this, k3);
WeakSet.prototype.add = function() {
called = true;
};
count = 1;
} else {
assertEq(k, k2);
orig.call(this, k4);
count = 2;
}
};
var arr = [k1, k2];
var m = new WeakSet(arr);
assertEq(called, false);
assertEq(count, 2);
assertEq(m.has(k1), false);
assertEq(m.has(k2), false);
assertEq(m.has(k3), true);
assertEq(m.has(k4), true);
WeakSet.prototype.add = orig;
}
function test_error() {
let orig = WeakSet.prototype.add;
var arr = [k1];
// WeakSet should throw TypeError if adder is not callable.
WeakSet.prototype.add = null;
assertThrowsInstanceOf(() => new WeakSet(arr), TypeError);
WeakSet.prototype.add = {};
assertThrowsInstanceOf(() => new WeakSet(arr), TypeError);
// WeakSet should propagate error thrown by adder.
WeakSet.prototype.add = function() {
throw SyntaxError();
};
assertThrowsInstanceOf(() => new WeakSet(arr), SyntaxError);
WeakSet.prototype.add = orig;
}
function test() {
test_patched();
test_proxy1();
test_proxy2();
test_change1();
test_change2();
test_error();
}
test();

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

@ -1,11 +0,0 @@
var s = 'Abc1234"\'\t987\u00ff';
assertEq(isLatin1(s), true);
assertEq(s.toSource(), '(new String("Abc1234\\"\'\\t987\\xFF"))');
var res = s.quote();
assertEq(res, '"Abc1234\\"\'\\t987\\xFF"');
assertEq(isLatin1(res), true);
s = 'Abc1234"\'\t\u1200987\u00ff';
assertEq(isLatin1(s), false);
assertEq(s.toSource(), '(new String("Abc1234\\"\'\\t\\u1200987\\xFF"))');
assertEq(s.quote(), '"Abc1234\\"\'\\t\\u1200987\\xFF"');

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

@ -4274,10 +4274,15 @@ LIRGenerator::visitBlock(MBasicBlock *block)
// basic block. This is used to handle fallible code which is moved/added
// into split edge blocks, which do not have resume points. See
// SplitCriticalEdgesForBlock.
//
// When folding conditions, we might create split-edge blocks which have
// multiple predecessors, in such case it is invalid to have any instruction
// in these blocks, as these blocks have no associated pc, thus we cannot
// safely bailout from such block.
if (lastResumePoint_) {
for (size_t s = 0; s < block->numSuccessors(); s++) {
MBasicBlock *succ = block->getSuccessor(s);
if (!succ->entryResumePoint()) {
if (!succ->entryResumePoint() && succ->numPredecessors() == 1) {
MOZ_ASSERT(succ->isSplitEdge());
MOZ_ASSERT(succ->phisBegin() == succ->phisEnd());
succ->setEntryResumePoint(lastResumePoint_);

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

@ -146,6 +146,13 @@ Sink(MIRGenerator *mir, MIRGraph &graph)
if (!ins->canClone())
continue;
// If the block is a split-edge block, which is created for folding
// test conditions, then the block has no resume point and has
// multiple predecessors. In such case, we cannot safely move
// bailing instruction to these blocks as we have no way to bailout.
if (!usesDominator->entryResumePoint() && usesDominator->numPredecessors() != 1)
continue;
JitSpewDef(JitSpew_Sink, " Can Clone & Recover, sink instruction\n", ins);
JitSpew(JitSpew_Sink, " into Block %u", usesDominator->id());

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

@ -3051,6 +3051,7 @@ GCRuntime::refillFreeListFromMainThread(JSContext *cx, AllocKind thingKind)
// instead of reporting it.
if (!allowGC) {
MOZ_ASSERT(!mustCollectNow);
js_ReportOutOfMemory(cx);
return nullptr;
}
@ -3099,7 +3100,12 @@ GCRuntime::refillFreeListOffMainThread(ExclusiveContext *cx, AllocKind thingKind
while (rt->isHeapBusy())
HelperThreadState().wait(GlobalHelperThreadState::PRODUCER);
return allocator->arenas.allocateFromArena(zone, thingKind, maybeStartBGAlloc);
void *thing = allocator->arenas.allocateFromArena(zone, thingKind, maybeStartBGAlloc);
if (thing)
return thing;
js_ReportOutOfMemory(cx);
return nullptr;
}
/* static */ void *

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

@ -482,24 +482,6 @@ IsString(HandleValue v)
#if JS_HAS_TOSOURCE
/*
* String.prototype.quote is generic (as are most string methods), unlike
* toSource, toString, and valueOf.
*/
static bool
str_quote(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedString str(cx, ThisToStringForStringProto(cx, args));
if (!str)
return false;
str = js_QuoteString(cx, str, '"');
if (!str)
return false;
args.rval().setString(str);
return true;
}
MOZ_ALWAYS_INLINE bool
str_toSource_impl(JSContext *cx, CallArgs args)
{
@ -3976,7 +3958,6 @@ str_concat(JSContext *cx, unsigned argc, Value *vp)
static const JSFunctionSpec string_methods[] = {
#if JS_HAS_TOSOURCE
JS_FN("quote", str_quote, 0,JSFUN_GENERIC_NATIVE),
JS_FN(js_toSource_str, str_toSource, 0,0),
#endif

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

@ -19,6 +19,8 @@
#include "jsobjinlines.h"
#include "vm/Interpreter-inl.h"
using namespace js;
using namespace js::gc;
@ -528,6 +530,20 @@ WeakMap_construct(JSContext *cx, unsigned argc, Value *vp)
// ES6 23.3.1.1 steps 5-6, 11.
if (!args.get(0).isNullOrUndefined()) {
// Steps 7a-b.
RootedValue adderVal(cx);
if (!JSObject::getProperty(cx, obj, obj, cx->names().set, &adderVal))
return false;
// Step 7c.
if (!IsCallable(adderVal))
return ReportIsNotFunction(cx, adderVal);
bool isOriginalAdder = IsNativeFunction(adderVal, WeakMap_set);
RootedValue mapVal(cx, ObjectValue(*obj));
FastInvokeGuard fig(cx, adderVal);
InvokeArgs &args2 = fig.args();
// Steps 7d-e.
JS::ForOfIterator iter(cx);
if (!iter.init(args[0]))
@ -566,14 +582,27 @@ WeakMap_construct(JSContext *cx, unsigned argc, Value *vp)
return false;
// Steps 12k-l.
if (keyVal.isPrimitive()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
return false;
}
if (isOriginalAdder) {
if (keyVal.isPrimitive()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
return false;
}
keyObject = &keyVal.toObject();
if (!SetWeakMapEntry(cx, obj, keyObject, val))
return false;
keyObject = &keyVal.toObject();
if (!SetWeakMapEntry(cx, obj, keyObject, val))
return false;
} else {
if (!args2.init(2))
return false;
args2.setCallee(adderVal);
args2.setThis(mapVal);
args2[0].set(keyVal);
args2[1].set(val);
if (!fig.invoke(cx))
return false;
}
}
}

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

@ -0,0 +1,25 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1106428;
var int32x4 = SIMD.int32x4;
var summary = 'int32x4 bool';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
var a = int32x4.bool(true, false, true, false);
assertEq(a.x, -1);
assertEq(a.y, 0);
assertEq(a.z, -1);
assertEq(a.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -1,50 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
/*
This test case uses String.quote(), because that method uses the JS printf()
functions internally. The printf() functions print to a char* buffer, causing
conversion to and from UTF-8 if UTF-8 is enabled. If not, UTF-8 sequences are
converted to ASCII \uXXXX sequences. Thus, both return values are acceptable.
*/
var BUGNUMBER = 315974;
var summary = 'Test internal printf() for wide characters';
printBugNumber(BUGNUMBER);
printStatus (summary);
enterFunc (String (BUGNUMBER));
var goodSurrogatePair = '\uD841\uDC42';
var badSurrogatePair = '\uD841badbad';
var goodSurrogatePairQuotedUtf8 = '"\uD841\uDC42"';
var badSurrogatePairQuotedUtf8 = 'no error thrown!';
var goodSurrogatePairQuotedNoUtf8 = '"\\uD841\\uDC42"';
var badSurrogatePairQuotedNoUtf8 = '"\\uD841badbad"';
var status = summary + ': String.quote() should pay respect to surrogate pairs';
var actual = goodSurrogatePair.quote();
/* Result in case UTF-8 is enabled. */
var expect = goodSurrogatePairQuotedUtf8;
/* Result in case UTF-8 is disabled. */
if (actual != expect && actual == goodSurrogatePairQuotedNoUtf8)
expect = actual;
reportCompare(expect, actual, status);
/*
* A malformed surrogate pair throws an out-of-memory error,
* but only if UTF-8 is enabled.
*/
status = summary + ': String.quote() should throw error on bad surrogate pair';
/* Out of memory is not catchable. */
actual = badSurrogatePair.quote();
/* Come here only if UTF-8 is disabled. */
reportCompare(badSurrogatePairQuotedNoUtf8, actual, status);
exitFunc (String (BUGNUMBER));

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

@ -14,8 +14,7 @@ var voids = [null, undefined];
function noop() { }
var generics = {
String: [{ quote: [] },
{ substring: [] },
String: [{ substring: [] },
{ toLowerCase: [] },
{ toUpperCase: [] },
{ charAt: [] },

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

@ -113,7 +113,7 @@ var Match =
switch (typeof exp) {
case "string":
if (act !== exp)
throw new MatchError("expected " + exp.quote() + ", got " + quote(act));
throw new MatchError("expected " + quote(exp) + ", got " + quote(act));
return true;
case "boolean":
case "number":
@ -131,7 +131,7 @@ var Match =
for (var key in exp) {
if (!(key in act))
throw new MatchError("expected property " + key.quote() + " not found in " + quote(act));
throw new MatchError("expected property " + quote(key) + " not found in " + quote(act));
match(act[key], exp[key]);
}

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

@ -12,6 +12,7 @@
#include "jsprototypes.h"
#define FOR_EACH_COMMON_PROPERTYNAME(macro) \
macro(add, add, "add") \
macro(anonymous, anonymous, "anonymous") \
macro(Any, Any, "Any") \
macro(apply, apply, "apply") \
@ -213,6 +214,7 @@
macro(variable, variable, "variable") \
macro(void0, void0, "(void 0)") \
macro(watch, watch, "watch") \
macro(WeakSet_add, WeakSet_add, "WeakSet_add") \
macro(writable, writable, "writable") \
macro(w, w, "w") \
macro(x, x, "x") \

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

@ -244,7 +244,7 @@ ShapeTable::search(jsid id, bool adding)
}
}
/* NOTREACHED */
MOZ_CRASH("Shape::search failed to find an expected entry.");
return nullptr;
}

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

@ -21,7 +21,7 @@ namespace mozilla {
template <typename T>
struct IsPixel : FalseType {};
// See struct decleration for a description of each unit type
// See struct declaration for a description of each unit type.
struct CSSPixel;
struct LayoutDevicePixel;
struct LayerPixel;

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

@ -2096,6 +2096,16 @@ ScrollFrameHelper::ScrollToWithOrigin(nsPoint aScrollPosition,
mLastSmoothScrollOrigin = aOrigin;
mScrollGeneration = ++sScrollGenerationCounter;
if (!nsLayoutUtils::GetDisplayPort(mOuter->GetContent())) {
// If this frame doesn't have a displayport then there won't be an
// APZC instance for it and so there won't be anything to process
// this smooth scroll request. We should set a displayport on this
// frame to force an APZC which can handle the request.
nsLayoutUtils::CalculateAndSetDisplayPortMargins(
mOuter->GetScrollTargetFrame(),
nsLayoutUtils::RepaintMode::DoNotRepaint);
}
// Schedule a paint to ensure that the frame metrics get updated on
// the compositor thread.
mOuter->SchedulePaint();

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

@ -238,7 +238,7 @@ var Addons = {
_getElementForAddon: function(aKey) {
let list = document.getElementById("addons-list");
let element = list.querySelector("div[addonID=" + aKey.quote() + "]");
let element = list.querySelector("div[addonID=\"" + CSS.escape(aKey) + "\"]");
return element;
},

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

@ -87,7 +87,7 @@ var NewPrefDialog = {
}
// If item already in list, it's being changed, else added
let item = document.querySelector(".pref-item[name=" + aPrefName.quote() + "]");
let item = document.querySelector(".pref-item[name=\"" + CSS.escape(aPrefName) + "\"]");
if (item) {
this._positiveButton.textContent = gStringBundle.GetStringFromName("newPref.changeButton");
} else {
@ -472,7 +472,7 @@ var AboutConfig = {
}
// If pref not already in list, refresh display as it's being added
let item = document.querySelector(".pref-item[name=" + pref.name.quote() + "]");
let item = document.querySelector(".pref-item[name=\"" + CSS.escape(pref.name) + "\"]");
if (!item) {
document.location.reload();
return;

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

@ -0,0 +1,27 @@
. "$topsrcdir/mobile/android/config/mozconfigs/common"
# L10n
ac_add_options --with-l10n-base=../../l10n-central
# Global options
ac_add_options --disable-tests
# Mozilla-Central nightlies only since this has a cost in performance
ac_add_options --enable-js-diagnostics
# Android
ac_add_options --with-android-min-sdk=10
ac_add_options --target=arm-linux-androideabi
ac_add_options --with-system-zlib
ac_add_options --enable-updater
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
export MOZILLA_OFFICIAL=1
export MOZ_DISABLE_GECKOVIEW=1
ac_add_options --with-branding=mobile/android/branding/nightly
ac_add_options --disable-stdcxx-compat
. "$topsrcdir/mobile/android/config/mozconfigs/common.override"

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

@ -0,0 +1,29 @@
. "$topsrcdir/mobile/android/config/mozconfigs/common"
# L10n
ac_add_options --with-l10n-base=../../l10n-central
# Global options
ac_add_options --disable-tests
# Mozilla-Central nightlies only since this has a cost in performance
ac_add_options --enable-js-diagnostics
# Android
ac_add_options --with-android-min-sdk=9
ac_add_options --with-android-max-sdk=9
ac_add_options --enable-android-resource-constrained
ac_add_options --target=arm-linux-androideabi
ac_add_options --with-system-zlib
ac_add_options --enable-updater
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
export MOZILLA_OFFICIAL=1
export MOZ_DISABLE_GECKOVIEW=1
ac_add_options --with-branding=mobile/android/branding/nightly
ac_add_options --disable-stdcxx-compat
. "$topsrcdir/mobile/android/config/mozconfigs/common.override"

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

@ -445,6 +445,10 @@ To see more help for a specific command, run:
fn = getattr(instance, handler.method)
if args.debug_command:
import pdb
pdb.set_trace()
try:
result = fn(**vars(args.command_args))
@ -603,6 +607,8 @@ To see more help for a specific command, run:
global_group.add_argument('-h', '--help', dest='help',
action='store_true', default=False,
help='Show this help message.')
global_group.add_argument('--debug-command', action='store_true',
help='Start a Python debugger when command is dispatched.')
for args, kwargs in self.global_arguments:
global_group.add_argument(*args, **kwargs)

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

@ -104,6 +104,55 @@ static const uint8_t PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA[] =
"\x30\x05\x82\x03" ".nc"
"\x30\x05\x82\x03" ".tf";
// If useRoots is true, we only use root certificates in the candidate list.
// If useRoots is false, we only use non-root certificates in the list.
static Result
FindIssuerInner(ScopedCERTCertList& candidates, bool useRoots,
Input encodedIssuerName, TrustDomain::IssuerChecker& checker,
/*out*/ bool& keepGoing)
{
keepGoing = true;
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
bool candidateIsRoot = !!n->cert->isRoot;
if (candidateIsRoot != useRoots) {
continue;
}
Input certDER;
Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
if (rv != Success) {
continue; // probably too big
}
Input anssiSubject;
rv = anssiSubject.Init(ANSSI_SUBJECT_DATA, sizeof(ANSSI_SUBJECT_DATA) - 1);
if (rv != Success) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
// TODO: Use CERT_CompareName or equivalent
if (InputsAreEqual(encodedIssuerName, anssiSubject)) {
Input anssiNameConstraints;
if (anssiNameConstraints.Init(
PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA,
sizeof(PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA) - 1)
!= Success) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
rv = checker.Check(certDER, &anssiNameConstraints, keepGoing);
} else {
rv = checker.Check(certDER, nullptr, keepGoing);
}
if (rv != Success) {
return rv;
}
if (!keepGoing) {
break;
}
}
return Success;
}
Result
NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName,
IssuerChecker& checker, Time)
@ -116,40 +165,19 @@ NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName,
&encodedIssuerNameSECItem, 0,
false));
if (candidates) {
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
Input certDER;
Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
if (rv != Success) {
continue; // probably too big
}
bool keepGoing;
Input anssiSubject;
rv = anssiSubject.Init(ANSSI_SUBJECT_DATA,
sizeof(ANSSI_SUBJECT_DATA) - 1);
if (rv != Success) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
// TODO: Use CERT_CompareName or equivalent
if (InputsAreEqual(encodedIssuerName, anssiSubject)) {
Input anssiNameConstraints;
if (anssiNameConstraints.Init(
PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA,
sizeof(PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA) - 1)
!= Success) {
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
rv = checker.Check(certDER, &anssiNameConstraints, keepGoing);
} else {
rv = checker.Check(certDER, nullptr, keepGoing);
}
// First, try all the root certs; then try all the non-root certs.
bool keepGoing;
Result rv = FindIssuerInner(candidates, true, encodedIssuerName, checker,
keepGoing);
if (rv != Success) {
return rv;
}
if (keepGoing) {
rv = FindIssuerInner(candidates, false, encodedIssuerName, checker,
keepGoing);
if (rv != Success) {
return rv;
}
if (!keepGoing) {
break;
}
}
}

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

@ -30,12 +30,17 @@ class GeckoInstance(object):
"browser.tabs.remote.autostart.1": False,
"browser.tabs.remote.autostart.2": False}
def __init__(self, host, port, bin, profile, app_args=None, symbols_path=None,
gecko_log=None, prefs=None):
def __init__(self, host, port, bin, profile=None, app_args=None, symbols_path=None,
gecko_log=None, prefs=None, ):
self.marionette_host = host
self.marionette_port = port
self.bin = bin
self.profile_path = profile
# Check if it is a Profile object or a path to profile
self.profile = None
if isinstance(profile, Profile):
self.profile = profile
else:
self.profile_path = profile
self.prefs = prefs
self.app_args = app_args or []
self.runner = None
@ -47,12 +52,14 @@ class GeckoInstance(object):
profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port
if self.prefs:
profile_args["preferences"].update(self.prefs)
if not self.profile_path:
profile_args["restore"] = False
profile = Profile(**profile_args)
else:
profile_args["path_from"] = self.profile_path
profile = Profile.clone(**profile_args)
if hasattr(self, "profile_path") and self.profile is None:
if not self.profile_path:
profile_args["restore"] = False
self.profile = Profile(**profile_args)
else:
profile_args["path_from"] = self.profile_path
self.profile = Profile.clone(**profile_args)
process_args = {
'processOutputLine': [NullOutput()],
@ -101,20 +108,27 @@ class GeckoInstance(object):
'MOZ_CRASHREPORTER_NO_REPORT': '1', })
self.runner = Runner(
binary=self.bin,
profile=profile,
profile=self.profile,
cmdargs=['-no-remote', '-marionette'] + self.app_args,
env=env,
symbols_path=self.symbols_path,
process_args=process_args)
self.runner.start()
def close(self):
def close(self, restart=False):
if not restart:
self.profile = None
if self.runner:
self.runner.stop()
self.runner.cleanup()
def restart(self, prefs=None):
self.close()
def restart(self, prefs=None, clean=True):
if clean:
self.profile.cleanup()
self.profile = None
self.close(restart=True)
if prefs:
self.prefs = prefs
else:

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

@ -475,6 +475,7 @@ class Marionette(object):
self.host = host
self.port = self.local_port = port
self.bin = bin
self.profile = profile
self.instance = None
self.session = None
self.session_id = None
@ -512,7 +513,7 @@ class Marionette(object):
KeyError):
instance_class = geckoinstance.GeckoInstance
self.instance = instance_class(host=self.host, port=self.port,
bin=self.bin, profile=profile,
bin=self.bin, profile=self.profile,
app_args=app_args, symbols_path=symbols_path,
gecko_log=gecko_log)
self.instance.start()
@ -528,7 +529,7 @@ class Marionette(object):
binary=emulator_binary,
userdata=emulator_img,
resolution=emulator_res,
profile=profile,
profile=self.profile,
adb_path=adb_path,
process_args=process_args)
self.emulator = self.runner.device
@ -773,20 +774,20 @@ class Marionette(object):
self.start_session()
self._reset_timeouts()
def restart_with_clean_profile(self):
def restart(self, clean=False):
"""
This will terminate the currently running instance, and spawn a new instance
with a clean profile.
with the same profile and then reuse the session id when creating a session again.
: param prefs: A dictionary whose keys are preference names.
"""
if not self.instance:
raise errors.MarionetteException("enforce_gecko_prefs can only be called " \
raise errors.MarionetteException("restart can only be called " \
"on gecko instances launched by Marionette")
self.delete_session()
self.instance.restart()
self.instance.restart(clean=clean)
assert(self.wait_for_port()), "Timed out waiting for port!"
self.start_session()
self.start_session(session_id=self.session_id)
self._reset_timeouts()
def absolute_url(self, relative_url):

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

@ -27,6 +27,12 @@ class TestLog(MarionetteTestCase):
self.assertFalse(bool_value)
def test_clean_profile(self):
self.marionette.restart_with_clean_profile()
self.marionette.restart(clean=True)
with self.assertRaisesRegexp(JavascriptException, "Error getting pref"):
bool_value = self.marionette.execute_script("return SpecialPowers.getBoolPref('marionette.test.bool');")
def test_can_restart_the_browser(self):
self.marionette.enforce_gecko_prefs({"marionette.test.restart": True})
self.marionette.restart()
bool_value = self.marionette.execute_script("return SpecialPowers.getBoolPref('marionette.test.restart');")
self.assertTrue(bool_value)

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

@ -54,10 +54,8 @@ class Emulator(Device):
self.sdcard = None
if sdcard:
self.sdcard = self.create_sdcard(sdcard)
self.userdata = os.path.join(self.arch.sysdir, 'userdata.img')
if userdata:
self.userdata = tempfile.NamedTemporaryFile(prefix='qemu-userdata')
shutil.copyfile(userdata, self.userdata)
self.userdata = tempfile.NamedTemporaryFile(prefix='qemu-userdata')
self.initdata = userdata if userdata else os.path.join(self.arch.sysdir, 'userdata.img')
self.no_window = no_window
self.battery = EmulatorBattery(self)
@ -72,7 +70,9 @@ class Emulator(Device):
qemu_args = [self.arch.binary,
'-kernel', self.arch.kernel,
'-sysdir', self.arch.sysdir,
'-data', self.userdata]
'-data', self.userdata.name,
'-initdata', self.initdata,
'-wipe-data']
if self.no_window:
qemu_args.append('-no-window')
if self.sdcard:
@ -162,7 +162,9 @@ class Emulator(Device):
if self.proc:
self.proc.kill()
self.proc = None
# Remove temporary user data image
if self.userdata:
self.userdata.close()
# Remove temporary sdcard
if self.sdcard and os.path.isfile(self.sdcard):
os.remove(self.sdcard)

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

@ -57,6 +57,7 @@
#include "mozilla/CycleCollectedJSRuntime.h"
#include <algorithm>
#include "mozilla/ArrayUtils.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DOMJSClass.h"
@ -96,6 +97,7 @@ class IncrementalFinalizeRunnable : public nsRunnable
nsTArray<nsISupports*> mSupports;
DeferredFinalizeArray mDeferredFinalizeFunctions;
uint32_t mFinalizeFunctionToRun;
bool mReleasing;
static const PRTime SliceMillis = 10; /* ms */
@ -1124,6 +1126,7 @@ IncrementalFinalizeRunnable::IncrementalFinalizeRunnable(CycleCollectedJSRuntime
DeferredFinalizerTable& aFinalizers)
: mRuntime(aRt)
, mFinalizeFunctionToRun(0)
, mReleasing(false)
{
this->mSupports.SwapElements(aSupports);
DeferredFinalizeFunctionHolder* function =
@ -1143,39 +1146,46 @@ IncrementalFinalizeRunnable::~IncrementalFinalizeRunnable()
void
IncrementalFinalizeRunnable::ReleaseNow(bool aLimited)
{
//MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mDeferredFinalizeFunctions.Length() != 0,
"We should have at least ReleaseSliceNow to run");
MOZ_ASSERT(mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length(),
"No more finalizers to run?");
if (mReleasing) {
MOZ_ASSERT(false, "Try to avoid re-entering ReleaseNow!");
return;
}
{
mozilla::AutoRestore<bool> ar(mReleasing);
mReleasing = true;
MOZ_ASSERT(mDeferredFinalizeFunctions.Length() != 0,
"We should have at least ReleaseSliceNow to run");
MOZ_ASSERT(mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length(),
"No more finalizers to run?");
TimeDuration sliceTime = TimeDuration::FromMilliseconds(SliceMillis);
TimeStamp started = TimeStamp::Now();
bool timeout = false;
do {
const DeferredFinalizeFunctionHolder& function =
mDeferredFinalizeFunctions[mFinalizeFunctionToRun];
if (aLimited) {
bool done = false;
while (!timeout && !done) {
/*
* We don't want to read the clock too often, so we try to
* release slices of 100 items.
*/
done = function.run(100, function.data);
timeout = TimeStamp::Now() - started >= sliceTime;
}
if (done) {
TimeDuration sliceTime = TimeDuration::FromMilliseconds(SliceMillis);
TimeStamp started = TimeStamp::Now();
bool timeout = false;
do {
const DeferredFinalizeFunctionHolder& function =
mDeferredFinalizeFunctions[mFinalizeFunctionToRun];
if (aLimited) {
bool done = false;
while (!timeout && !done) {
/*
* We don't want to read the clock too often, so we try to
* release slices of 100 items.
*/
done = function.run(100, function.data);
timeout = TimeStamp::Now() - started >= sliceTime;
}
if (done) {
++mFinalizeFunctionToRun;
}
if (timeout) {
break;
}
} else {
function.run(UINT32_MAX, function.data);
++mFinalizeFunctionToRun;
}
if (timeout) {
break;
}
} else {
function.run(UINT32_MAX, function.data);
++mFinalizeFunctionToRun;
}
} while (mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length());
} while (mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length());
}
if (mFinalizeFunctionToRun == mDeferredFinalizeFunctions.Length()) {
MOZ_ASSERT(mRuntime->mFinalizeRunnable == this);
@ -1210,7 +1220,21 @@ IncrementalFinalizeRunnable::Run()
void
CycleCollectedJSRuntime::FinalizeDeferredThings(DeferredFinalizeType aType)
{
MOZ_ASSERT(!mFinalizeRunnable);
/*
* If the previous GC created a runnable to finalize objects
* incrementally, and if it hasn't finished yet, finish it now. We
* don't want these to build up. We also don't want to allow any
* existing incremental finalize runnables to run after a
* non-incremental GC, since they are often used to detect leaks.
*/
if (mFinalizeRunnable) {
mFinalizeRunnable->ReleaseNow(false);
if (mFinalizeRunnable) {
// If we re-entered ReleaseNow, we couldn't delete mFinalizeRunnable and
// we need to just continue processing it.
return;
}
}
mFinalizeRunnable = new IncrementalFinalizeRunnable(this,
mDeferredSupports,
mDeferredFinalizerTable);
@ -1261,17 +1285,6 @@ CycleCollectedJSRuntime::OnGC(JSGCStatus aStatus)
}
#endif
/*
* If the previous GC created a runnable to finalize objects
* incrementally, and if it hasn't finished yet, finish it now. We
* don't want these to build up. We also don't want to allow any
* existing incremental finalize runnables to run after a
* non-incremental GC, since they are often used to detect leaks.
*/
if (mFinalizeRunnable) {
mFinalizeRunnable->ReleaseNow(false);
}
// Do any deferred finalization of native objects.
FinalizeDeferredThings(JS::WasIncrementalGC(mJSRuntime) ? FinalizeIncrementally :
FinalizeNow);

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

@ -11,7 +11,6 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@ -27,6 +26,7 @@
#if defined(HAVE_SYS_QUOTA_H) && defined(HAVE_LINUX_QUOTA_H)
#define USE_LINUX_QUOTACTL
#include <sys/mount.h>
#include <sys/quota.h>
#endif