Merge m-c to f-t

This commit is contained in:
Phil Ringnalda 2015-01-17 18:33:04 -08:00
commit d89e692f9b
34 changed files with 302 additions and 167 deletions

View File

@ -495,7 +495,7 @@ TabChildBase::GetDOMWindowUtils()
}
already_AddRefed<nsIDocument>
TabChildBase::GetDocument()
TabChildBase::GetDocument() const
{
nsCOMPtr<nsIDOMDocument> domDoc;
WebNavigation()->GetDocument(getter_AddRefs(domDoc));
@ -2114,7 +2114,8 @@ TabChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid&
return true;
}
CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid,
GetPresShellResolution());
nsString data;
data.AppendLiteral("{ \"x\" : ");
data.AppendFloat(point.x);
@ -2142,7 +2143,9 @@ TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid&
return true;
}
LayoutDevicePoint currentPoint = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid) * mWidget->GetDefaultScale();;
LayoutDevicePoint currentPoint =
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
* mWidget->GetDefaultScale();;
if (!mActiveElementManager->ActiveElementUsesStyle()) {
// If the active element isn't visually affected by the :active style, we
// have no need to wait the extra sActiveDurationMs to make the activation
@ -2194,7 +2197,7 @@ TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& a
bool eventHandled =
DispatchMouseEvent(NS_LITERAL_STRING("contextmenu"),
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid),
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution()),
2, 1, 0, true,
nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
@ -2203,7 +2206,8 @@ TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& a
// If no one handle context menu, fire MOZLONGTAP event
if (!eventHandled) {
LayoutDevicePoint currentPoint =
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid) * mWidget->GetDefaultScale();
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
* mWidget->GetDefaultScale();
int time = 0;
nsEventStatus status =
DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, mWidget);
@ -2662,6 +2666,17 @@ TabChild::SendSetTargetAPZCNotification(const WidgetTouchEvent& aEvent,
SendSetTargetAPZCNotification(shell, aInputBlockId, targets, waitForRefresh);
}
float
TabChild::GetPresShellResolution() const
{
nsCOMPtr<nsIDocument> document(GetDocument());
nsIPresShell* shell = document->GetShell();
if (!shell) {
return 1.0f;
}
return shell->GetXResolution();
}
bool
TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
@ -2670,7 +2685,9 @@ TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
TABC_LOG("Receiving touch event of type %d\n", aEvent.message);
for (size_t i = 0; i < aEvent.touches.Length(); i++) {
aEvent.touches[i]->mRefPoint = APZCCallbackHelper::ApplyCallbackTransform(aEvent.touches[i]->mRefPoint, aGuid, mWidget->GetDefaultScale());
aEvent.touches[i]->mRefPoint = APZCCallbackHelper::ApplyCallbackTransform(
aEvent.touches[i]->mRefPoint, aGuid, mWidget->GetDefaultScale(),
GetPresShellResolution());
}
if (aEvent.message == NS_TOUCH_START && IsAsyncPanZoomEnabled()) {

View File

@ -180,7 +180,7 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TabChildBase)
virtual nsIWebNavigation* WebNavigation() = 0;
virtual nsIWebNavigation* WebNavigation() const = 0;
virtual nsIWidget* WebWidget() = 0;
nsIPrincipal* GetPrincipal() { return mPrincipal; }
bool IsAsyncPanZoomEnabled();
@ -206,7 +206,7 @@ protected:
// Get the DOMWindowUtils for the top-level window in this tab.
already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils();
// Get the Document for the top-level window in this tab.
already_AddRefed<nsIDocument> GetDocument();
already_AddRefed<nsIDocument> GetDocument() const;
// Wrapper for nsIDOMWindowUtils.setCSSViewport(). This updates some state
// variables local to this class before setting it.
@ -418,7 +418,7 @@ public:
PIndexedDBPermissionRequestChild* aActor)
MOZ_OVERRIDE;
virtual nsIWebNavigation* WebNavigation() MOZ_OVERRIDE { return mWebNav; }
virtual nsIWebNavigation* WebNavigation() const MOZ_OVERRIDE { return mWebNav; }
virtual nsIWidget* WebWidget() MOZ_OVERRIDE { return mWidget; }
/** Return the DPI of the widget this TabChild draws to. */
@ -611,6 +611,9 @@ private:
const mozilla::layers::ScrollableLayerGuid& aGuid,
const uint64_t& aInputBlockId);
// Get the pres shell resolution of the document in this tab.
float GetPresShellResolution() const;
void SetTabId(const TabId& aTabId)
{
MOZ_ASSERT(mUniqueId == 0);

View File

@ -312,8 +312,18 @@ APZCCallbackHelper::UpdateCallbackTransform(const FrameMetrics& aApzcMetrics, co
}
CSSPoint
APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput, const ScrollableLayerGuid& aGuid)
APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
const ScrollableLayerGuid& aGuid,
float aPresShellResolution)
{
// First, scale inversely by the pres shell resolution to cancel the
// scale-to-resolution transform that the compositor adds to the layer with
// the pres shell resolution. The points sent to Gecko by APZ don't have
// this transform unapplied (unlike other compositor-side transforms)
// because APZ doesn't know about it.
CSSPoint input = aInput / aPresShellResolution;
// Now apply the callback-transform.
// XXX: technically we need to walk all the way up the layer tree from the layer
// represented by |aGuid.mScrollId| up to the root of the layer tree and apply
// the input transforms at each level in turn. However, it is quite difficult
@ -331,20 +341,21 @@ APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput, const Scrolla
void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
if (property) {
CSSPoint delta = (*static_cast<CSSPoint*>(property));
return aInput + delta;
return input + delta;
}
}
}
return aInput;
return input;
}
nsIntPoint
APZCCallbackHelper::ApplyCallbackTransform(const nsIntPoint& aPoint,
const ScrollableLayerGuid& aGuid,
const CSSToLayoutDeviceScale& aScale)
const ScrollableLayerGuid& aGuid,
const CSSToLayoutDeviceScale& aScale,
float aPresShellResolution)
{
LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y);
point = ApplyCallbackTransform(point / aScale, aGuid) * aScale;
point = ApplyCallbackTransform(point / aScale, aGuid, aPresShellResolution) * aScale;
LayoutDeviceIntPoint ret = gfx::RoundedToInt(point);
return nsIntPoint(ret.x, ret.y);
}

View File

@ -89,16 +89,21 @@ public:
/* Apply an "input transform" to the given |aInput| and return the transformed value.
The input transform applied is the one for the content element corresponding to
|aGuid|; this is populated in a previous call to UpdateCallbackTransform. See that
method's documentations for details. */
method's documentations for details.
This method additionally adjusts |aInput| by inversely scaling by the provided
pres shell resolution, to cancel out a compositor-side transform (added in
bug 1076241) that APZ doesn't unapply. */
static CSSPoint ApplyCallbackTransform(const CSSPoint& aInput,
const ScrollableLayerGuid& aGuid);
const ScrollableLayerGuid& aGuid,
float aPresShellResolution);
/* Same as above, but operates on nsIntPoint that are assumed to be in LayoutDevice
pixel space. Requires an additonal |aScale| parameter to convert between CSS and
LayoutDevice space. */
static nsIntPoint ApplyCallbackTransform(const nsIntPoint& aPoint,
const ScrollableLayerGuid& aGuid,
const CSSToLayoutDeviceScale& aScale);
const CSSToLayoutDeviceScale& aScale,
float aPresShellResolution);
};
}

View File

@ -1249,6 +1249,7 @@ CompositorParent* CompositorParent::RemoveCompositor(uint64_t id)
bool
CompositorParent::RecvNotifyChildCreated(const uint64_t& child)
{
MonitorAutoLock lock(*sIndirectLayerTreesLock);
NotifyChildCreated(child);
return true;
}
@ -1256,7 +1257,7 @@ CompositorParent::RecvNotifyChildCreated(const uint64_t& child)
void
CompositorParent::NotifyChildCreated(const uint64_t& aChild)
{
MonitorAutoLock lock(*sIndirectLayerTreesLock);
sIndirectLayerTreesLock->AssertCurrentThreadOwns();
sIndirectLayerTrees[aChild].mParent = this;
sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
}
@ -1264,8 +1265,8 @@ CompositorParent::NotifyChildCreated(const uint64_t& aChild)
bool
CompositorParent::RecvAdoptChild(const uint64_t& child)
{
NotifyChildCreated(child);
MonitorAutoLock lock(*sIndirectLayerTreesLock);
NotifyChildCreated(child);
if (sIndirectLayerTrees[child].mLayerTree) {
sIndirectLayerTrees[child].mLayerTree->mLayerManager = mLayerManager;
}

View File

@ -77,28 +77,6 @@ ComputeImageFlags(ImageURL* uri, bool isMultiPart)
return imageFlags;
}
/* static */ bool
ImageFactory::CanRetargetOnDataAvailable(ImageURL* aURI, bool aIsMultiPart)
{
// We can't retarget OnDataAvailable safely in cases where we aren't storing
// source data (and thus need to sync decode in ODA) because allocating frames
// off-main-thread is currently not possible and we don't have a workaround in
// place yet. (See bug 967985.) For now, we detect those cases and refuse to
// retarget. When the problem is fixed, this function can be removed.
if (aIsMultiPart) {
return false;
}
uint32_t imageFlags = ComputeImageFlags(aURI, aIsMultiPart);
if (!(imageFlags & Image::INIT_FLAG_DISCARDABLE) &&
!(imageFlags & Image::INIT_FLAG_DECODE_ON_DRAW)) {
return false;
}
return true;
}
/* static */ already_AddRefed<Image>
ImageFactory::CreateImage(nsIRequest* aRequest,
ProgressTracker* aProgressTracker,

View File

@ -28,14 +28,6 @@ public:
*/
static void Initialize();
/**
* Determines whether it's safe to retarget OnDataAvailable for an image.
*
* @param aURI The URI of the image.
* @param aIsMultipart Whether the image is part of a multipart request.
*/
static bool CanRetargetOnDataAvailable(ImageURL* aURI, bool aIsMultiPart);
/**
* Creates a new image with the given properties.
* Can be called on or off the main thread.

View File

@ -1178,12 +1178,6 @@ RasterImage::OnImageDataAvailable(nsIRequest*,
return rv;
}
/* static */ already_AddRefed<nsIEventTarget>
RasterImage::GetEventTarget()
{
return DecodePool::Singleton()->GetEventTarget();
}
nsresult
RasterImage::SetSourceSizeHint(uint32_t aSizeHint)
{

View File

@ -242,8 +242,6 @@ public:
nsresult aStatus,
bool aLastPart) MOZ_OVERRIDE;
static already_AddRefed<nsIEventTarget> GetEventTarget();
/**
* A hint of the number of bytes of source data that the image contains. If
* called early on, this can help reduce copying and reallocations by

View File

@ -9,6 +9,7 @@
#include "imgLoader.h"
#include "imgRequestProxy.h"
#include "DecodePool.h"
#include "ProgressTracker.h"
#include "ImageFactory.h"
#include "Image.h"
@ -694,14 +695,14 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
nsCOMPtr<nsIThreadRetargetableRequest> retargetable =
do_QueryInterface(aRequest);
if (httpChannel && retargetable &&
ImageFactory::CanRetargetOnDataAvailable(mURI, mIsMultiPartChannel)) {
if (httpChannel && retargetable) {
nsAutoCString mimeType;
nsresult rv = httpChannel->GetContentType(mimeType);
if (NS_SUCCEEDED(rv) && !mimeType.EqualsLiteral(IMAGE_SVG_XML)) {
// Image object not created until OnDataAvailable, so forward to static
// DecodePool directly.
nsCOMPtr<nsIEventTarget> target = RasterImage::GetEventTarget();
nsCOMPtr<nsIEventTarget> target =
DecodePool::Singleton()->GetEventTarget();
rv = retargetable->RetargetDeliveryTo(target);
}
PR_LOG(GetImgLog(), PR_LOG_WARNING,

View File

@ -340,6 +340,30 @@ GCParameter(JSContext *cx, unsigned argc, Value *vp)
return true;
}
static void
SetAllowRelazification(JSContext *cx, bool allow)
{
JSRuntime *rt = cx->runtime();
MOZ_ASSERT(rt->allowRelazificationForTesting != allow);
rt->allowRelazificationForTesting = allow;
for (AllFramesIter i(cx); !i.done(); ++i)
i.script()->setDoNotRelazify(allow);
}
static bool
RelazifyFunctions(JSContext *cx, unsigned argc, Value *vp)
{
// Relazifying functions on GC is usually only done for compartments that are
// not active. To aid fuzzing, this testing function allows us to relazify
// even if the compartment is active.
SetAllowRelazification(cx, true);
bool res = GC(cx, argc, vp);
SetAllowRelazification(cx, false);
return res;
}
static bool
IsProxy(JSContext *cx, unsigned argc, Value *vp)
{
@ -2236,6 +2260,11 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
"gcparam(name [, value])",
" Wrapper for JS_[GS]etGCParameter. The name is one of " GC_PARAMETER_ARGS_LIST),
JS_FN_HELP("relazifyFunctions", RelazifyFunctions, 0, 0,
"relazifyFunctions(...)",
" Perform a GC and allow relazification of functions. Accepts the same\n"
" arguments as gc()."),
JS_FN_HELP("getBuildConfiguration", GetBuildConfiguration, 0, 0,
"getBuildConfiguration()",
" Return an object describing some of the configuration options SpiderMonkey\n"

View File

@ -1977,10 +1977,12 @@ template <class T, class U>
static inline void
PropagateTransitiveParseFlags(const T *inner, U *outer)
{
if (inner->bindingsAccessedDynamically())
outer->setBindingsAccessedDynamically();
if (inner->hasDebuggerStatement())
outer->setHasDebuggerStatement();
if (inner->bindingsAccessedDynamically())
outer->setBindingsAccessedDynamically();
if (inner->hasDebuggerStatement())
outer->setHasDebuggerStatement();
if (inner->hasDirectEval())
outer->setHasDirectEval();
}
template <typename ParseHandler>
@ -7586,6 +7588,7 @@ Parser<ParseHandler>::memberExpr(TokenKind tt, bool allowCallSyntax)
/* Select JSOP_EVAL and flag pc as heavyweight. */
op = pc->sc->strict ? JSOP_STRICTEVAL : JSOP_EVAL;
pc->sc->setBindingsAccessedDynamically();
pc->sc->setHasDirectEval();
/*
* In non-strict mode code, direct calls to eval can add

View File

@ -58,11 +58,15 @@ class AnyContextFlags
// scope chain.
bool hasDebuggerStatement:1;
// A direct eval occurs in the body of the script.
bool hasDirectEval:1;
public:
AnyContextFlags()
: hasExplicitUseStrict(false),
bindingsAccessedDynamically(false),
hasDebuggerStatement(false)
hasDebuggerStatement(false),
hasDirectEval(false)
{ }
};
@ -195,10 +199,12 @@ class SharedContext
bool hasExplicitUseStrict() const { return anyCxFlags.hasExplicitUseStrict; }
bool bindingsAccessedDynamically() const { return anyCxFlags.bindingsAccessedDynamically; }
bool hasDebuggerStatement() const { return anyCxFlags.hasDebuggerStatement; }
bool hasDirectEval() const { return anyCxFlags.hasDirectEval; }
void setExplicitUseStrict() { anyCxFlags.hasExplicitUseStrict = true; }
void setBindingsAccessedDynamically() { anyCxFlags.bindingsAccessedDynamically = true; }
void setHasDebuggerStatement() { anyCxFlags.hasDebuggerStatement = true; }
void setHasDirectEval() { anyCxFlags.hasDirectEval = true; }
inline bool allLocalsAliased();

View File

@ -0,0 +1,16 @@
// |jit-test| error: TypeError
function newFunc(x) { new Function(x)(); };
newFunc("\
function GetUnicodeValues(c) {\
u = new Array();\
if ((c >= 0x0100 && c < 0x0138) || (c > 0x1Bedb && c < 0x0178))\
return;\
return u;\
}\
function Unicode(c) {\
u = GetUnicodeValues(c);\
this.upper = u[0];\
}\
for (var i = 0; i <= 0x017f; i++) { var U = new Unicode(i); }\
");

View File

@ -0,0 +1,16 @@
function f(x) {
return x * 3;
}
for (var i=0; i<100; i++) {
f(i);
}
relazifyFunctions();
f(1);
f(1);
relazifyFunctions();
for (var i=0; i<10; i++) {
f.call(null, i);
}

View File

@ -2087,29 +2087,6 @@ JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
extern JS_PUBLIC_API(void)
JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
#ifdef JS_DEBUG
/*
* Debug-only method to dump the object graph of heap-allocated things.
*
* fp: file for the dump output.
* start: when non-null, dump only things reachable from start
* thing. Otherwise dump all things reachable from the
* runtime roots.
* startKind: trace kind of start if start is not null. Must be
* JSTRACE_OBJECT when start is null.
* thingToFind: dump only paths in the object graph leading to thingToFind
* when non-null.
* maxDepth: the upper bound on the number of edges to descend from the
* graph roots.
* thingToIgnore: thing to ignore during the graph traversal when non-null.
*/
extern JS_PUBLIC_API(bool)
JS_DumpHeap(JSRuntime *rt, FILE *fp, void* startThing, JSGCTraceKind kind,
void *thingToFind, size_t maxDepth, void *thingToIgnore);
#endif
/*
* Garbage collector API.
*/

View File

@ -486,17 +486,22 @@ js::fun_resolve(JSContext *cx, HandleObject obj, HandleId id, bool *resolvedp)
MOZ_ASSERT(!IsInternalFunctionObject(obj));
RootedValue v(cx);
uint32_t attrs;
// Since f.length and f.name are configurable, they could be resolved
// and then deleted:
// function f(x) {}
// assertEq(f.length, 1);
// delete f.length;
// assertEq(f.name, "f");
// delete f.name;
// Afterwards, asking for f.length or f.name again will cause this
// resolve hook to run again. Defining the property again the second
// time through would be a bug.
// assertEq(f.length, 0); // gets Function.prototype.length!
// assertEq(f.name, ""); // gets Function.prototype.name!
// We use the RESOLVED_LENGTH and RESOLVED_NAME flags as a hack to prevent this
// bug.
if (isLength) {
// Since f.length is configurable, it could be resolved and then deleted:
// function f(x) {}
// assertEq(f.length, 1);
// delete f.length;
// Afterwards, asking for f.length again will cause this resolve
// hook to run again. Defining the property again the second
// time through would be a bug.
// assertEq(f.length, 0); // gets Function.prototype.length!
// We use the RESOLVED_LENGTH flag as a hack to prevent this bug.
if (fun->hasResolvedLength())
return true;
@ -505,17 +510,20 @@ js::fun_resolve(JSContext *cx, HandleObject obj, HandleId id, bool *resolvedp)
uint16_t length = fun->hasScript() ? fun->nonLazyScript()->funLength() :
fun->nargs() - fun->hasRest();
v.setInt32(length);
attrs = JSPROP_READONLY;
} else {
if (fun->hasResolvedName())
return true;
v.setString(fun->atom() == nullptr ? cx->runtime()->emptyString : fun->atom());
attrs = JSPROP_READONLY | JSPROP_PERMANENT;
}
if (!NativeDefineProperty(cx, fun, id, v, nullptr, nullptr, attrs))
if (!NativeDefineProperty(cx, fun, id, v, nullptr, nullptr, JSPROP_READONLY))
return false;
if (isLength)
fun->setResolvedLength();
else
fun->setResolvedName();
*resolvedp = true;
return true;
@ -754,7 +762,9 @@ JSFunction::trace(JSTracer *trc)
// This information can either be a LazyScript, or the name of a
// self-hosted function which can be cloned over again. The latter
// is stored in the first extended slot.
if (IS_GC_MARKING_TRACER(trc) && !compartment()->hasBeenEntered() &&
JSRuntime *rt = trc->runtime();
if (IS_GC_MARKING_TRACER(trc) &&
(rt->allowRelazificationForTesting || !compartment()->hasBeenEntered()) &&
!compartment()->isDebuggee() && !compartment()->isSelfHosting &&
u.i.s.script_->isRelazifiable() && (!isSelfHostedBuiltin() || isExtended()))
{
@ -1412,12 +1422,19 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
RootedScript script(cx, lazy->maybeScript());
// Only functions without inner functions or direct eval are
// re-lazified. Functions with either of those are on the static scope
// chain of their inner functions, or in the case of eval, possibly
// eval'd inner functions. This prohibits re-lazification as
// StaticScopeIter queries isHeavyweight of those functions, which
// requires a non-lazy script.
bool canRelazify = !lazy->numInnerFunctions() && !lazy->hasDirectEval();
if (script) {
fun->setUnlazifiedScript(script);
// Remember the lazy script on the compiled script, so it can be
// stored on the function again in case of re-lazification.
// Only functions without inner functions are re-lazified.
if (!lazy->numInnerFunctions())
if (canRelazify)
script->setLazyScript(lazy);
return true;
}
@ -1441,7 +1458,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
// Additionally, the lazy script cache is not used during incremental
// GCs, to avoid resurrecting dead scripts after incremental sweeping
// has started.
if (!lazy->numInnerFunctions() && !JS::IsIncrementalGCInProgress(cx->runtime())) {
if (canRelazify && !JS::IsIncrementalGCInProgress(cx->runtime())) {
LazyScriptCache::Lookup lookup(cx, lazy);
cx->runtime()->lazyScriptCache.lookup(lookup, script.address());
}
@ -1486,7 +1503,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
lazy->initScript(script);
// Try to insert the newly compiled script into the lazy script cache.
if (!lazy->numInnerFunctions()) {
if (canRelazify) {
// A script's starting column isn't set by the bytecode emitter, so
// specify this from the lazy script so that if an identical lazy
// script is encountered later a match can be determined.
@ -1517,7 +1534,7 @@ JSFunction::relazify(JSTracer *trc)
{
JSScript *script = nonLazyScript();
MOZ_ASSERT(script->isRelazifiable());
MOZ_ASSERT(!compartment()->hasBeenEntered());
MOZ_ASSERT(trc->runtime()->allowRelazificationForTesting || !compartment()->hasBeenEntered());
MOZ_ASSERT(!compartment()->isDebuggee());
// If the script's canonical function isn't lazy, we have to mark the

View File

@ -48,6 +48,7 @@ class JSFunction : public js::NativeObject
INTERPRETED_LAZY = 0x1000, /* function is interpreted but doesn't have a script yet */
ARROW = 0x2000, /* ES6 '(args) => body' syntax */
RESOLVED_LENGTH = 0x4000, /* f.length has been resolved (see js::fun_resolve). */
RESOLVED_NAME = 0x8000, /* f.name has been resolved (see js::fun_resolve). */
/* Derived Flags values for convenience: */
NATIVE_FUN = 0,
@ -134,6 +135,7 @@ class JSFunction : public js::NativeObject
bool isArrow() const { return flags() & ARROW; }
bool hasResolvedLength() const { return flags() & RESOLVED_LENGTH; }
bool hasResolvedName() const { return flags() & RESOLVED_NAME; }
bool hasJITCode() const {
if (!hasScript())
@ -206,6 +208,10 @@ class JSFunction : public js::NativeObject
flags_ |= RESOLVED_LENGTH;
}
void setResolvedName() {
flags_ |= RESOLVED_NAME;
}
JSAtom *atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
js::PropertyName *name() const {

View File

@ -3789,6 +3789,7 @@ LazyScript::CreateRaw(ExclusiveContext *cx, HandleFunction fun,
p.strict = false;
p.bindingsAccessedDynamically = false;
p.hasDebuggerStatement = false;
p.hasDirectEval = false;
p.directlyInsideEval = false;
p.usesArgumentsApplyAndThis = false;

View File

@ -1012,6 +1012,11 @@ class JSScript : public js::gc::TenuredCell
// correctly.
bool typesGeneration_:1;
// Do not relazify this script. This is only used by the relazify()
// testing function for scripts that are on the stack. Usually we don't
// relazify functions in compartments with scripts on the stack.
bool doNotRelazify_:1;
// Add padding so JSScript is gc::Cell aligned. Make padding protected
// instead of private to suppress -Wunused-private-field compiler warnings.
protected:
@ -1316,6 +1321,10 @@ class JSScript : public js::gc::TenuredCell
typesGeneration_ = (bool) generation;
}
void setDoNotRelazify(bool b) {
doNotRelazify_ = b;
}
bool hasAnyIonScript() const {
return hasIonScript();
}
@ -1395,7 +1404,7 @@ class JSScript : public js::gc::TenuredCell
bool isRelazifiable() const {
return (selfHosted() || lazyScript) &&
!isGenerator() && !hasBaselineScript() && !hasAnyIonScript();
!isGenerator() && !hasBaselineScript() && !hasAnyIonScript() && !doNotRelazify_;
}
void setLazyScript(js::LazyScript *lazy) {
lazyScript = lazy;
@ -1873,7 +1882,7 @@ class LazyScript : public gc::TenuredCell
uint32_t version : 8;
uint32_t numFreeVariables : 24;
uint32_t numInnerFunctions : 23;
uint32_t numInnerFunctions : 22;
uint32_t generatorKindBits : 2;
@ -1881,6 +1890,7 @@ class LazyScript : public gc::TenuredCell
uint32_t strict : 1;
uint32_t bindingsAccessedDynamically : 1;
uint32_t hasDebuggerStatement : 1;
uint32_t hasDirectEval : 1;
uint32_t directlyInsideEval : 1;
uint32_t usesArgumentsApplyAndThis : 1;
uint32_t hasBeenCloned : 1;
@ -2006,6 +2016,13 @@ class LazyScript : public gc::TenuredCell
p_.hasDebuggerStatement = true;
}
bool hasDirectEval() const {
return p_.hasDirectEval;
}
void setHasDirectEval() {
p_.hasDirectEval = true;
}
bool directlyInsideEval() const {
return p_.directlyInsideEval;
}

View File

@ -1,19 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
function fn() {
return function f(a, b, c) { };
}
assertEq(testLenientAndStrict('var f = fn(); f.name = "g"; f.name',
returns("f"), raisesException(TypeError)),
true);
assertEq(testLenientAndStrict('var f = fn(); delete f.name',
returns(false), raisesException(TypeError)),
true);
reportCompare(true, true);

View File

@ -0,0 +1,64 @@
function testFunctionName(f) {
var name = f.name;
f.name = 'g';
assertEq(f.name, name);
assertEq(delete f.name, true);
assertEq(f.name, '');
assertEq(f.hasOwnProperty('name'), false);
f.name = 'g';
assertEq(f.name, '');
Object.defineProperty(f, 'name', {value: 'g'});
assertEq(f.name, 'g');
}
function testFunctionNameStrict(f) {
"use strict";
var name = f.name;
var error;
try {
f.name = 'g';
} catch (e) {
error = e;
}
assertEq(f.name, name);
assertEq(error instanceof TypeError, true);
assertEq(delete f.name, true);
assertEq(f.name, '');
assertEq(f.hasOwnProperty('name'), false);
error = null;
try {
f.name = 'g';
} catch (e) {
error = e;
}
assertEq(f.name, '');
assertEq(error instanceof TypeError, true);
Object.defineProperty(f, 'name', {value: 'g'});
assertEq(f.name, 'g');
}
assertEq(Object.getOwnPropertyDescriptor(Object, "name").writable, false);
assertEq(Object.getOwnPropertyDescriptor(Object, "name").enumerable, false);
assertEq(Object.getOwnPropertyDescriptor(Object, "name").configurable, true);
assertEq(Object.getOwnPropertyDescriptor(Object, "name").value, 'Object');
assertEq(Object.getOwnPropertyDescriptor(function f(){}, "name").writable, false);
assertEq(Object.getOwnPropertyDescriptor(function f(){}, "name").enumerable, false);
assertEq(Object.getOwnPropertyDescriptor(function f(){}, "name").configurable, true);
assertEq(Object.getOwnPropertyDescriptor(function f(){}, "name").value, 'f');
// Basic test ensuring that Object.defineProperty works on pristine function.
function f() {};
Object.defineProperty(f, 'name', {value: 'g'});
assertEq(f.name, 'g');
// .name behaves as expected on scripted function.
testFunctionName(function f(){});
testFunctionNameStrict(function f(){});
// .name behaves as expected on builtin function.
testFunctionName(Function.prototype.apply);
testFunctionNameStrict(Function.prototype.call);
// .name behaves as expected on self-hosted builtin function.
testFunctionName(Array.prototype.forEach);
testFunctionNameStrict(Array.prototype.some);
if (typeof reportCompare === "function")
reportCompare(0, 0);

View File

@ -183,6 +183,7 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime)
suppressProfilerSampling(false),
hadOutOfMemory(false),
haveCreatedContext(false),
allowRelazificationForTesting(false),
data(nullptr),
signalHandlersInstalled_(false),
canUseSignalHandlers_(false),

View File

@ -1051,6 +1051,12 @@ struct JSRuntime : public JS::shadow::Runtime,
/* A context has been created on this runtime. */
bool haveCreatedContext;
/*
* Allow relazifying functions in compartments that are active. This is
* only used by the relazifyFunctions() testing function.
*/
bool allowRelazificationForTesting;
/* Linked list of all Debugger objects in the runtime. */
mozilla::LinkedList<js::Debugger> debuggerList;

View File

@ -1167,29 +1167,31 @@ ScopeIter::ScopeIter(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc
}
void
ScopeIter::settle()
ScopeIter::incrementStaticScopeIter()
{
ssi_++;
// For named lambdas, DeclEnvObject scopes are always attached to their
// CallObjects. Skip it here, as they are special cased in users of
// ScopeIter.
if (!ssi_.done() && ssi_.type() == StaticScopeIter<CanGC>::NamedLambda)
ssi_++;
}
void
ScopeIter::settle()
{
// Check for trying to iterate a heavyweight function frame before
// the prologue has created the CallObject, in which case we have to skip.
if (frame_ && frame_.isNonEvalFunctionFrame() &&
frame_.fun()->isHeavyweight() && !frame_.hasCallObj())
{
MOZ_ASSERT(ssi_.type() == StaticScopeIter<CanGC>::Function);
ssi_++;
incrementStaticScopeIter();
}
// Check if we have left the extent of the initial frame. This check must
// come between the named lambda check above and the direct eval check
// below. We must check the static scope after skipping the named lambda,
// as an SSI settled on a named lambda scope has no static scope. We must
// check the static scope before skipping the direct eval, as by then we
// would have already left the frame.
// Check if we have left the extent of the initial frame after we've
// settled on a static scope.
if (frame_ && (ssi_.done() || maybeStaticScope() == frame_.script()->enclosingStaticScope()))
frame_ = NullFramePtr();
@ -1224,7 +1226,7 @@ ScopeIter::operator++()
scope_ = &scope_->as<DeclEnvObject>().enclosingScope();
}
ssi_++;
incrementStaticScopeIter();
settle();
return *this;

View File

@ -724,6 +724,7 @@ class ScopeIter
RootedObject scope_;
AbstractFramePtr frame_;
void incrementStaticScopeIter();
void settle();
// No value semantics.

View File

@ -10,6 +10,7 @@
#include "CacheFileOutputStream.h"
#include "nsThreadUtils.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Move.h"
#include <algorithm>
#include "nsComponentManagerUtils.h"
#include "nsProxyRelease.h"
@ -999,13 +1000,13 @@ CacheFile::Lock()
void
CacheFile::Unlock()
{
nsTArray<nsISupports*> objs;
// move the elements out of mObjsToRelease
// so that they can be released after we unlock
nsTArray<nsRefPtr<nsISupports>> objs;
objs.SwapElements(mObjsToRelease);
mLock.Unlock();
for (uint32_t i = 0; i < objs.Length(); i++)
objs[i]->Release();
}
void
@ -1015,11 +1016,11 @@ CacheFile::AssertOwnsLock() const
}
void
CacheFile::ReleaseOutsideLock(nsISupports *aObject)
CacheFile::ReleaseOutsideLock(nsRefPtr<nsISupports> aObject)
{
AssertOwnsLock();
mObjsToRelease.AppendElement(aObject);
mObjsToRelease.AppendElement(Move(aObject));
}
nsresult
@ -1438,8 +1439,7 @@ CacheFile::RemoveChunkInternal(CacheFileChunk *aChunk, bool aCacheChunk)
AssertOwnsLock();
aChunk->mActiveChunk = false;
ReleaseOutsideLock(static_cast<CacheFileChunkListener *>(
aChunk->mFile.forget().take()));
ReleaseOutsideLock(nsRefPtr<CacheFileChunkListener>(aChunk->mFile.forget()).forget());
if (aCacheChunk) {
mCachedChunks.Put(aChunk->Index(), aChunk);
@ -1542,7 +1542,7 @@ CacheFile::RemoveInput(CacheFileInputStream *aInput, nsresult aStatus)
found = mInputs.RemoveElement(aInput);
MOZ_ASSERT(found);
ReleaseOutsideLock(static_cast<nsIInputStream*>(aInput));
ReleaseOutsideLock(already_AddRefed<nsIInputStream>(static_cast<nsIInputStream*>(aInput)));
if (!mMemoryOnly)
WriteMetadataIfNeededLocked();
@ -1835,8 +1835,9 @@ CacheFile::WriteAllCachedChunks(const uint32_t& aIdx,
MOZ_ASSERT(aChunk->IsReady());
NS_ADDREF(aChunk);
file->ReleaseOutsideLock(aChunk);
// this would be cleaner if we had an nsRefPtr constructor
// that took a nsRefPtr<Derived>
file->ReleaseOutsideLock(nsRefPtr<nsISupports>(aChunk));
return PL_DHASH_REMOVE;
}
@ -1927,7 +1928,7 @@ CacheFile::PadChunkWithZeroes(uint32_t aChunkIdx)
rv = chunk->EnsureBufSize(kChunkSize);
if (NS_FAILED(rv)) {
ReleaseOutsideLock(chunk.forget().take());
ReleaseOutsideLock(chunk.forget());
SetError(rv);
return rv;
}
@ -1936,7 +1937,7 @@ CacheFile::PadChunkWithZeroes(uint32_t aChunkIdx)
chunk->UpdateDataSize(chunk->DataSize(), kChunkSize - chunk->DataSize(),
false);
ReleaseOutsideLock(chunk.forget().take());
ReleaseOutsideLock(chunk.forget());
return NS_OK;
}

View File

@ -121,7 +121,7 @@ private:
void Lock();
void Unlock();
void AssertOwnsLock() const;
void ReleaseOutsideLock(nsISupports *aObject);
void ReleaseOutsideLock(nsRefPtr<nsISupports> aObject);
enum ECallerType {
READER = 0,
@ -216,7 +216,7 @@ private:
nsTArray<CacheFileInputStream*> mInputs;
CacheFileOutputStream *mOutput;
nsTArray<nsISupports*> mObjsToRelease;
nsTArray<nsRefPtr<nsISupports>> mObjsToRelease;
};
class CacheFileAutoLock {

View File

@ -444,7 +444,7 @@ CacheFileInputStream::ReleaseChunk()
mWaitingForUpdate = false;
}
mFile->ReleaseOutsideLock(mChunk.forget().take());
mFile->ReleaseOutsideLock(mChunk.forget());
}
void

View File

@ -344,7 +344,7 @@ CacheFileOutputStream::ReleaseChunk()
LOG(("CacheFileOutputStream::ReleaseChunk() [this=%p, idx=%d]",
this, mChunk->Index()));
mFile->ReleaseOutsideLock(mChunk.forget().take());
mFile->ReleaseOutsideLock(mChunk.forget());
}
void

View File

@ -223,13 +223,13 @@ function test_clearedSpec()
function test_escapeQueryBrackets()
{
var url = stringToURL("http://example.com/?a[x]=1");
do_check_eq(url.spec, "http://example.com/?a%5Bx%5D=1");
do_check_eq(url.spec, "http://example.com/?a[x]=1");
url = stringToURL("http://example.com/?a%5Bx%5D=1");
do_check_eq(url.spec, "http://example.com/?a%5Bx%5D=1");
url = stringToURL("http://[2001::1]/?a[x]=1");
do_check_eq(url.spec, "http://[2001::1]/?a%5Bx%5D=1");
do_check_eq(url.spec, "http://[2001::1]/?a[x]=1");
url = stringToURL("http://[2001::1]/?a%5Bx%5D=1");
do_check_eq(url.spec, "http://[2001::1]/?a%5Bx%5D=1");

View File

@ -9,15 +9,6 @@ const Cc = SpecialPowers.Cc;
function test() {
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
const isOSXMavericks = navigator.userAgent.indexOf("Mac OS X 10.9") != -1;
const isOSXYosemite = navigator.userAgent.indexOf("Mac OS X 10.10") != -1;
if (isOSXMtnLion || isOSXMavericks || isOSXYosemite ) {
todo(false, "This test fails on OS X 10.8, 10.9, 10.10, see bug 786938");
SimpleTest.finish();
return;
}
// set up the web handler object
var webHandler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
createInstance(SpecialPowers.Ci.nsIWebHandlerApp);

View File

@ -7,5 +7,5 @@ support-files =
[test_badMimeType.html]
[test_handlerApps.xhtml]
skip-if = toolkit == 'android'
skip-if = (toolkit == 'android' || os == 'mac') # OS X: bug 786938
[test_unsafeBidiChars.xhtml]

View File

@ -363,7 +363,7 @@ static const uint32_t EscapeChars[256] =
0,1023, 0, 512,1023, 0,1023, 0,1023,1023,1023,1023,1023,1023, 953, 784, // 2x !"#$%&'()*+,-./
1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1008,1008, 0,1008, 0, 768, // 3x 0123456789:;<=>?
1008,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, // 4x @ABCDEFGHIJKLMNO
1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 0, 896, 0, 896,1023, // 5x PQRSTUVWXYZ[\]^_
1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 896, 896, 896, 896,1023, // 5x PQRSTUVWXYZ[\]^_
0,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, // 6x `abcdefghijklmno
1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 896,1012, 896,1023, 0, // 7x pqrstuvwxyz{|}~ DEL
0 // 80 to FF are zero