Merge m-c to fx-team.

This commit is contained in:
Ryan VanderMeulen 2013-08-08 16:25:37 -04:00
commit 759170e174
83 changed files with 1016 additions and 298 deletions

View File

@ -442,8 +442,6 @@ nsPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin)
NS_IMETHODIMP
nsPrincipal::GetAppStatus(uint16_t* aAppStatus)
{
MOZ_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
*aAppStatus = GetAppStatus();
return NS_OK;
}
@ -569,8 +567,8 @@ nsPrincipal::Write(nsIObjectOutputStream* aStream)
uint16_t
nsPrincipal::GetAppStatus()
{
MOZ_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
NS_WARN_IF_FALSE(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Asking for app status on a principal with an unknown app id");
// Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID)
// and they are not inside a mozbrowser.
if (mAppId == nsIScriptSecurityManager::NO_APP_ID ||

View File

@ -1953,15 +1953,6 @@ nsDocument::Init()
mRadioGroups.Init();
mCustomPrototypes.Init();
// If after creation the owner js global is not set for a document
// we use the default compartment for this document, instead of creating
// wrapper in some random compartment when the document is exposed to js
// via some events.
nsCOMPtr<nsIGlobalObject> global = xpc::GetJunkScopeGlobal();
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
mScopeObject = do_GetWeakReference(global);
MOZ_ASSERT(mScopeObject);
// Force initialization.
nsINode::nsSlots* slots = Slots();
@ -1992,6 +1983,15 @@ nsDocument::Init()
NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!");
// If after creation the owner js global is not set for a document
// we use the default compartment for this document, instead of creating
// wrapper in some random compartment when the document is exposed to js
// via some events.
nsCOMPtr<nsIGlobalObject> global = xpc::GetJunkScopeGlobal();
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
mScopeObject = do_GetWeakReference(global);
MOZ_ASSERT(mScopeObject);
mScriptLoader = new nsScriptLoader(this);
mImageTracker.Init();
@ -2545,37 +2545,26 @@ nsDocument::InitCSP(nsIChannel* aChannel)
}
// Figure out if we need to apply an app default CSP or a CSP from an app manifest
bool applyAppDefaultCSP = false;
bool applyAppManifestCSP = false;
nsIPrincipal* principal = NodePrincipal();
bool unknownAppId;
uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
nsAutoString appManifestCSP;
if (NS_SUCCEEDED(principal->GetUnknownAppId(&unknownAppId)) &&
!unknownAppId &&
NS_SUCCEEDED(principal->GetAppStatus(&appStatus))) {
applyAppDefaultCSP = ( appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED ||
appStatus == nsIPrincipal::APP_STATUS_CERTIFIED);
uint16_t appStatus = principal->GetAppStatus();
bool applyAppDefaultCSP = appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED ||
appStatus == nsIPrincipal::APP_STATUS_CERTIFIED;
bool applyAppManifestCSP = false;
if (appStatus != nsIPrincipal::APP_STATUS_NOT_INSTALLED) {
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
if (appsService) {
uint32_t appId = 0;
if (NS_SUCCEEDED(principal->GetAppId(&appId))) {
appsService->GetCSPByLocalId(appId, appManifestCSP);
if (!appManifestCSP.IsEmpty()) {
applyAppManifestCSP = true;
}
nsAutoString appManifestCSP;
if (appStatus != nsIPrincipal::APP_STATUS_NOT_INSTALLED) {
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
if (appsService) {
uint32_t appId = 0;
if (NS_SUCCEEDED(principal->GetAppId(&appId))) {
appsService->GetCSPByLocalId(appId, appManifestCSP);
if (!appManifestCSP.IsEmpty()) {
applyAppManifestCSP = true;
}
}
}
}
#ifdef PR_LOGGING
else
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to get app status from principal"));
#endif
// If there's no CSP to apply, go ahead and return early
if (!applyAppDefaultCSP &&

View File

@ -245,6 +245,7 @@ nsSMILCSSProperty::IsPropertyAnimatable(nsCSSProperty aPropID)
case eCSSProperty_stroke_opacity:
case eCSSProperty_stroke_width:
case eCSSProperty_text_anchor:
case eCSSProperty_text_blink:
case eCSSProperty_text_decoration:
case eCSSProperty_text_decoration_line:
case eCSSProperty_text_rendering:

View File

@ -3540,6 +3540,14 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
JS::Rooted<JSObject*> global(cx);
bool defineOnXray = xpc::WrapperFactory::IsXrayWrapper(obj);
if (defineOnXray) {
// Check whether to define this property on the Xray first. This allows
// consumers to opt in to defining on the xray even if they don't want
// to define on the underlying global.
if (name_struct->mConstructorEnabled &&
!(*name_struct->mConstructorEnabled)(cx, obj)) {
return NS_OK;
}
global = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
if (!global) {
return NS_ERROR_DOM_SECURITY_ERR;
@ -3549,36 +3557,36 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
global = obj;
}
// Check whether our constructor is enabled after we unwrap Xrays, since
// we don't want to define an interface on the Xray if it's disabled in
// the target global, even if it's enabled in the Xray's global.
if (name_struct->mConstructorEnabled &&
!(*name_struct->mConstructorEnabled)(cx, global)) {
// Check whether to define on the global too. Note that at this point cx
// is in the compartment of global even if we were coming in via an Xray.
bool defineOnGlobal = !name_struct->mConstructorEnabled ||
(*name_struct->mConstructorEnabled)(cx, global);
if (!defineOnGlobal && !defineOnXray) {
return NS_OK;
}
bool enabled;
JS::Rooted<JSObject*> interfaceObject(cx, define(cx, global, id, &enabled));
if (enabled) {
if (!interfaceObject) {
JS::Rooted<JSObject*> interfaceObject(cx, define(cx, global, id,
defineOnGlobal));
if (!interfaceObject) {
return NS_ERROR_FAILURE;
}
if (defineOnXray) {
// This really should be handled by the Xray for the window.
ac.destroy();
if (!JS_WrapObject(cx, interfaceObject.address()) ||
!JS_DefinePropertyById(cx, obj, id,
JS::ObjectValue(*interfaceObject), JS_PropertyStub,
JS_StrictPropertyStub, 0)) {
return NS_ERROR_FAILURE;
}
if (defineOnXray) {
// This really should be handled by the Xray for the window.
ac.destroy();
if (!JS_WrapObject(cx, interfaceObject.address()) ||
!JS_DefinePropertyById(cx, obj, id,
JS::ObjectValue(*interfaceObject), JS_PropertyStub,
JS_StrictPropertyStub, 0)) {
return NS_ERROR_FAILURE;
}
}
*did_resolve = true;
return NS_OK;
}
*did_resolve = true;
return NS_OK;
}
}

View File

@ -371,7 +371,7 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
JS::Handle<JSObject*> proto,
const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties,
const char* name)
const char* name, bool defineOnGlobal)
{
JS::Rooted<JSObject*> constructor(cx);
if (constructorClass) {
@ -455,7 +455,7 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
return NULL;
}
if (!DefineConstructor(cx, global, name, constructor)) {
if (defineOnGlobal && !DefineConstructor(cx, global, name, constructor)) {
return nullptr;
}
@ -471,8 +471,9 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
JS::ObjectValue(*proto), JS_PropertyStub,
JS_StrictPropertyStub,
JSPROP_PERMANENT | JSPROP_READONLY) ||
!DefineConstructor(cx, global, namedConstructors->mName,
namedConstructor)) {
(defineOnGlobal &&
!DefineConstructor(cx, global, namedConstructors->mName,
namedConstructor))) {
return nullptr;
}
js::SetReservedSlot(constructor, namedConstructorSlot++,
@ -562,7 +563,7 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
JS::Heap<JSObject*>* constructorCache, const DOMClass* domClass,
const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties,
const char* name)
const char* name, bool defineOnGlobal)
{
MOZ_ASSERT(protoClass || constructorClass || constructor,
"Need at least one class or a constructor!");
@ -612,7 +613,8 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
interface = CreateInterfaceObject(cx, global, constructorProto,
constructorClass, constructor,
ctorNargs, namedConstructors, proto,
properties, chromeOnlyProperties, name);
properties, chromeOnlyProperties, name,
defineOnGlobal);
if (!interface) {
if (protoCache) {
// If we fail we need to make sure to clear the value of protoCache we

View File

@ -364,6 +364,12 @@ struct NamedConstructor
* on objects in chrome compartments. This must be null if the
* interface doesn't have any ChromeOnly properties or if the
* object is being created in non-chrome compartment.
* defineOnGlobal controls whether properties should be defined on the given
* global for the interface object (if any) and named
* constructors (if any) for this interface. This can be
* false in situations where we want the properties to only
* appear on privileged Xrays but not on the unprivileged
* underlying global.
*
* At least one of protoClass, constructorClass or constructor should be
* non-null. If constructorClass or constructor are non-null, the resulting
@ -380,7 +386,7 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
JS::Heap<JSObject*>* constructorCache, const DOMClass* domClass,
const NativeProperties* regularProperties,
const NativeProperties* chromeOnlyProperties,
const char* name);
const char* name, bool defineOnGlobal);
/*
* Define the unforgeable attributes on an object.

View File

@ -597,6 +597,9 @@ class CGHeaders(CGWrapper):
dictionary, if passed, to decide what to do with interface types.
"""
assert not descriptor or not dictionary
if t.nullable() and dictionary:
# Need to make sure that Nullable as a dictionary member works
declareIncludes.add("mozilla/dom/Nullable.h")
unrolled = t.unroll()
if unrolled.isUnion():
# UnionConversions.h includes UnionTypes.h
@ -604,7 +607,11 @@ class CGHeaders(CGWrapper):
elif unrolled.isInterface():
if unrolled.isSpiderMonkeyInterface():
bindingHeaders.add("jsfriendapi.h")
bindingHeaders.add("mozilla/dom/TypedArray.h")
if dictionary:
headerSet = declareIncludes
else:
headerSet = bindingHeaders
headerSet.add("mozilla/dom/TypedArray.h")
else:
providers = getRelevantProviders(descriptor, dictionary,
config)
@ -1657,7 +1664,8 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
def __init__(self, descriptor, properties):
args = [Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aGlobal'),
Argument('JS::Heap<JSObject*>*', 'protoAndIfaceArray')]
Argument('JS::Heap<JSObject*>*', 'aProtoAndIfaceArray'),
Argument('bool', 'aDefineOnGlobal')]
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
self.properties = properties
def definition_body(self):
@ -1784,13 +1792,13 @@ if (!unforgeableHolder) {
if needInterfacePrototypeObject:
protoClass = "&PrototypeClass.mBase"
protoCache = "&protoAndIfaceArray[prototypes::id::%s]" % self.descriptor.name
protoCache = "&aProtoAndIfaceArray[prototypes::id::%s]" % self.descriptor.name
else:
protoClass = "nullptr"
protoCache = "nullptr"
if needInterfaceObject:
interfaceClass = "&InterfaceObjectClass.mBase"
interfaceCache = "&protoAndIfaceArray[constructors::id::%s]" % self.descriptor.name
interfaceCache = "&aProtoAndIfaceArray[constructors::id::%s]" % self.descriptor.name
else:
# We don't have slots to store the named constructors.
assert len(self.descriptor.interface.namedConstructors) == 0
@ -1821,7 +1829,7 @@ if (!unforgeableHolder) {
" %s,\n"
" %s,\n"
" %s,\n"
" %s);" % (
" %s, aDefineOnGlobal);" % (
protoClass, protoCache,
interfaceClass, constructHookHolder, constructArgs,
namedConstructors,
@ -1833,7 +1841,7 @@ if (!unforgeableHolder) {
if UseHolderForUnforgeable(self.descriptor):
assert needInterfacePrototypeObject
setUnforgeableHolder = CGGeneric(
"JSObject* proto = protoAndIfaceArray[prototypes::id::%s];\n"
"JSObject* proto = aProtoAndIfaceArray[prototypes::id::%s];\n"
"if (proto) {\n"
" js::SetReservedSlot(proto, DOM_INTERFACE_PROTO_SLOTS_BASE,\n"
" JS::ObjectValue(*unforgeableHolder));\n"
@ -1851,9 +1859,9 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
A method for getting a per-interface object (a prototype object or interface
constructor object).
"""
def __init__(self, descriptor, name, idPrefix=""):
def __init__(self, descriptor, name, idPrefix="", extraArgs=[]):
args = [Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aGlobal')]
Argument('JS::Handle<JSObject*>', 'aGlobal')] + extraArgs
CGAbstractMethod.__init__(self, descriptor, name,
'JS::Handle<JSObject*>', args, inline=True)
self.id = idPrefix + "id::" + self.descriptor.name
@ -1867,7 +1875,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
/* Check to see whether the interface objects are already installed */
JS::Heap<JSObject*>* protoAndIfaceArray = GetProtoAndIfaceArray(aGlobal);
if (!protoAndIfaceArray[%s]) {
CreateInterfaceObjects(aCx, aGlobal, protoAndIfaceArray);
CreateInterfaceObjects(aCx, aGlobal, protoAndIfaceArray, aDefineOnGlobal);
}
/*
@ -1890,15 +1898,18 @@ class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
def definition_body(self):
return """
/* Get the interface prototype object for this class. This will create the
object as needed. */""" + CGGetPerInterfaceObject.definition_body(self)
object as needed. */
bool aDefineOnGlobal = true;""" + CGGetPerInterfaceObject.definition_body(self)
class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
"""
A method for getting the interface constructor object.
"""
def __init__(self, descriptor):
CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject",
"constructors::")
CGGetPerInterfaceObject.__init__(
self, descriptor, "GetConstructorObject",
"constructors::",
extraArgs=[Argument("bool", "aDefineOnGlobal", "true")])
def definition_body(self):
return """
/* Get the interface object for this class. This will create the object as
@ -1913,7 +1924,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
args = [Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aGlobal'),
Argument('JS::Handle<jsid>', 'id'),
Argument('bool*', 'aEnabled')]
Argument('bool', 'aDefineOnGlobal')]
CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'JSObject*', args)
def declare(self):
@ -1928,7 +1939,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
def definition_body(self):
if len(self.descriptor.interface.namedConstructors) > 0:
getConstructor = """ JSObject* interfaceObject = GetConstructorObject(aCx, aGlobal);
getConstructor = """ JSObject* interfaceObject = GetConstructorObject(aCx, aGlobal, aDefineOnGlobal);
if (!interfaceObject) {
return nullptr;
}
@ -1940,10 +1951,8 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
}
return interfaceObject;"""
else:
getConstructor = " return GetConstructorObject(aCx, aGlobal);"
return (""" *aEnabled = true;
""" + getConstructor)
getConstructor = " return GetConstructorObject(aCx, aGlobal, aDefineOnGlobal);"
return getConstructor
class CGConstructorEnabledViaPrefEnabled(CGAbstractMethod):
"""
@ -6098,6 +6107,10 @@ ${methods}
private:
friend class ${structName}Argument;
// Disallow copy-construction and assignment
${structName}(const ${structName}&) MOZ_DELETE;
void operator=(const ${structName}&) MOZ_DELETE;
${destructors}
enum Type {
@ -6221,6 +6234,10 @@ ${methods}
JS::MutableHandle<JS::Value> rval) const;
private:
// Disallow copy-construction and assignment
${structName}ReturnValue(const ${structName}ReturnValue&) MOZ_DELETE;
void operator=(const ${structName}ReturnValue&) MOZ_DELETE;
enum Type {
eUninitialized,
${enumValues}

View File

@ -1971,7 +1971,8 @@ function isSimpleModifiableElement(node) {
if (["A", "FONT", "S", "SPAN", "STRIKE", "U"].indexOf(node.tagName) != -1
&& node.hasAttribute("style")
&& (node.style.length == 1
|| (node.style.length == 3
|| (node.style.length == 4
&& "MozTextBlink" in node.style
&& "MozTextDecorationColor" in node.style
&& "MozTextDecorationLine" in node.style
&& "MozTextDecorationStyle" in node.style)

View File

@ -817,24 +817,25 @@ RetrieveTransaction.prototype = Object.create(CancellableTransaction.prototype,
this.registerRunCallback(callback);
this.retryCount = 0;
let that = this;
this.retrieve((function retryCallback(mmsStatus, msg) {
let retryCallback = (function (mmsStatus, msg) {
if (MMS.MMS_PDU_STATUS_DEFERRED == mmsStatus &&
that.retryCount < PREF_RETRIEVAL_RETRY_COUNT) {
if (that.timer == null) {
that.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.retryCount < PREF_RETRIEVAL_RETRY_COUNT) {
let time = PREF_RETRIEVAL_RETRY_INTERVALS[this.retryCount];
if (DEBUG) debug("Fail to retrieve. Will retry after: " + time);
if (this.timer == null) {
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
}
that.timer.initWithCallback((function (){
this.retrieve(retryCallback);
}).bind(that),
PREF_RETRIEVAL_RETRY_INTERVALS[that.retryCount],
Ci.nsITimer.TYPE_ONE_SHOT);
that.retryCount++;
this.timer.initWithCallback(this.retrieve.bind(this, retryCallback),
time, Ci.nsITimer.TYPE_ONE_SHOT);
this.retryCount++;
return;
}
this.runCallbackIfValid(mmsStatus, msg);
}).bind(this));
}).bind(this);
this.retrieve(retryCallback);
},
enumerable: true,
configurable: true,
@ -1043,6 +1044,10 @@ SendTransaction.prototype = Object.create(CancellableTransaction.prototype, {
if ((MMS.MMS_PDU_ERROR_TRANSIENT_FAILURE == mmsStatus ||
MMS.MMS_PDU_ERROR_PERMANENT_FAILURE == mmsStatus) &&
this.retryCount < PREF_SEND_RETRY_COUNT) {
if (DEBUG) {
debug("Fail to send. Will retry after: " + PREF_SEND_RETRY_INTERVAL);
}
if (this.timer == null) {
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
}
@ -1400,7 +1405,7 @@ MmsService.prototype = {
// Retrieved fail after retry, so we update the delivery status in DB and
// notify this domMessage that error happen.
gMobileMessageDatabaseService
.setMessageDeliveryByMessageId(id,
.setMessageDeliveryByMessageId(savableMessage.id,
null,
null,
DELIVERY_STATUS_ERROR,

View File

@ -13,4 +13,9 @@ LIBRARY_NAME = dompromise_s
LIBXUL_LIBRARY = 1
FAIL_ON_WARNINGS := 1
LOCAL_INCLUDES += \
-I$(topsrcdir)/dom/workers \
-I$(topsrcdir)/dom/base \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -11,6 +11,8 @@
#include "PromiseCallback.h"
#include "nsContentUtils.h"
#include "nsPIDOMWindow.h"
#include "WorkerPrivate.h"
#include "nsJSPrincipals.h"
namespace mozilla {
namespace dom {
@ -110,6 +112,26 @@ Promise::PrefEnabled()
return Preferences::GetBool("dom.promise.enabled", false);
}
/* static */ bool
Promise::EnabledForScope(JSContext* aCx, JSObject* /* unused */)
{
// Enable if the pref is enabled or if we're chrome or if we're a
// certified app.
if (PrefEnabled()) {
return true;
}
// Note that we have no concept of a certified app in workers.
// XXXbz well, why not?
if (!NS_IsMainThread()) {
return workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker();
}
nsIPrincipal* prin = nsContentUtils::GetSubjectPrincipal();
return nsContentUtils::IsSystemPrincipal(prin) ||
prin->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
}
static void
EnterCompartment(Maybe<JSAutoCompartment>& aAc, JSContext* aCx,
const Optional<JS::Handle<JS::Value> >& aValue)
@ -125,8 +147,6 @@ EnterCompartment(Maybe<JSAutoCompartment>& aAc, JSContext* aCx,
Promise::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
PromiseInit& aInit, ErrorResult& aRv)
{
MOZ_ASSERT(PrefEnabled());
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);
@ -155,8 +175,6 @@ Promise::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx,
JS::Handle<JS::Value> aValue, ErrorResult& aRv)
{
MOZ_ASSERT(PrefEnabled());
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);
@ -174,8 +192,6 @@ Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx,
Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx,
JS::Handle<JS::Value> aValue, ErrorResult& aRv)
{
MOZ_ASSERT(PrefEnabled());
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);

View File

@ -41,6 +41,7 @@ public:
~Promise();
static bool PrefEnabled();
static bool EnabledForScope(JSContext* aCx, JSObject* /* unused */);
// WebIDL

View File

@ -12647,10 +12647,11 @@ let ICCContactHelper = {
return;
}
// Check if contact has additional properties (email, anr, ...etc) need
// to be updated as well.
// Check if contact has additional properties (email, anr, ...etc) that
// need to be updated as well.
if ((field === USIM_PBR_EMAIL && !contact.email) ||
(field === USIM_PBR_ANR0 && !contact.anr[0])) {
(field === USIM_PBR_ANR0 && (!Array.isArray(contact.anr) ||
!contact.anr[0]))) {
updateField();
return;
}

View File

@ -7,6 +7,7 @@
* http://dom.spec.whatwg.org/#promises
*/
[Func="mozilla::dom::Promise::EnabledForScope"]
interface PromiseResolver {
// TODO bug 875289 - void fulfill(optional any value);
void resolve(optional any value);
@ -16,12 +17,18 @@ interface PromiseResolver {
callback PromiseInit = void (PromiseResolver resolver);
callback AnyCallback = any (optional any value);
[PrefControlled, Constructor(PromiseInit init)]
[Func="mozilla::dom::Promise::EnabledForScope", Constructor(PromiseInit init)]
interface Promise {
// TODO bug 875289 - static Promise fulfill(any value);
[Creator, Throws]
// Disable the static methods when the interface object is supposed to be
// disabled, just in case some code decides to walk over to .constructor from
// the proto of a promise object or someone screws up and manages to create a
// Promise object in this scope without having resolved the interface object
// first.
[Creator, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
static Promise resolve(any value); // same as any(value)
[Creator, Throws]
[Creator, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
static Promise reject(any value);
[Creator]

View File

@ -856,6 +856,10 @@ class SkipRoot
void init(js::ContextFriendFields *cx, const T *ptr, size_t count) {}
public:
~SkipRoot() {
// An empty destructor is needed to avoid warnings from clang about
// unused local variables of this type.
}
#endif /* DEBUG && JSGC_ROOT_ANALYSIS */

View File

@ -23,6 +23,8 @@
#include "jsatominlines.h"
#include "jsobjinlines.h"
using mozilla::DebugOnly;
using namespace js;
/*
@ -1552,7 +1554,7 @@ StructType::layout(JSContext *cx, HandleObject structType, HandleObject fields)
// If the field type is a BinaryType and we can't get its bytes, we have a problem.
RootedValue fieldTypeBytes(cx);
bool r = JSObject::getProperty(cx, fieldType, fieldType, cx->names().bytes, &fieldTypeBytes);
DebugOnly<bool> r = JSObject::getProperty(cx, fieldType, fieldType, cx->names().bytes, &fieldTypeBytes);
JS_ASSERT(r);
JS_ASSERT(fieldTypeBytes.isInt32());

View File

@ -18,6 +18,8 @@
#include "jsgcinlines.h"
#include "vm/ObjectImpl-inl.h"
using namespace js;
using namespace js::gc;

View File

@ -140,6 +140,44 @@ ion::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
return retval;
}
IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
const IonFrameIterator &frame)
: IonFrameIterator(activations),
machine_(frame.machineState())
{
returnAddressToFp_ = frame.returnAddressToFp();
topIonScript_ = frame.ionScript();
const OsiIndex *osiIndex = frame.osiIndex();
current_ = (uint8_t *) frame.fp();
type_ = IonFrame_OptimizedJS;
topFrameSize_ = frame.frameSize();
snapshotOffset_ = osiIndex->snapshotOffset();
}
uint32_t
ion::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
const ExceptionBailoutInfo &excInfo,
BaselineBailoutInfo **bailoutInfo)
{
JS_ASSERT(cx->isExceptionPending());
cx->mainThread().ionTop = NULL;
JitActivationIterator jitActivations(cx->runtime());
IonBailoutIterator iter(jitActivations, frame.frame());
JitActivation *activation = jitActivations.activation()->asJit();
*bailoutInfo = NULL;
uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo, &excInfo);
JS_ASSERT(retval == BAILOUT_RETURN_OK ||
retval == BAILOUT_RETURN_FATAL_ERROR ||
retval == BAILOUT_RETURN_OVERRECURSED);
JS_ASSERT((retval == BAILOUT_RETURN_OK) == (*bailoutInfo != NULL));
return retval;
}
// Initialize the decl env Object, call object, and any arguments obj of the current frame.
bool
ion::EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp)
@ -156,19 +194,26 @@ ion::EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp)
bool
ion::CheckFrequentBailouts(JSContext *cx, JSScript *script)
{
// Invalidate if this script keeps bailing out without invalidation. Next time
// we compile this script LICM will be disabled.
if (script->hasIonScript()) {
// Invalidate if this script keeps bailing out without invalidation. Next time
// we compile this script LICM will be disabled.
IonScript *ionScript = script->ionScript();
if (script->hasIonScript() &&
script->ionScript()->numBailouts() >= js_IonOptions.frequentBailoutThreshold &&
!script->hadFrequentBailouts)
{
script->hadFrequentBailouts = true;
if (ionScript->numBailouts() >= js_IonOptions.frequentBailoutThreshold &&
!script->hadFrequentBailouts)
{
script->hadFrequentBailouts = true;
IonSpew(IonSpew_Invalidate, "Invalidating due to too many bailouts");
IonSpew(IonSpew_Invalidate, "Invalidating due to too many bailouts");
if (!Invalidate(cx, script))
return false;
if (!Invalidate(cx, script))
return false;
} else {
// If we keep bailing out to handle exceptions, invalidate and
// forbid compilation.
if (ionScript->numExceptionBailouts() >= js_IonOptions.exceptionBailoutThreshold)
ForbidCompilation(cx, script);
}
}
return true;

View File

@ -125,6 +125,7 @@ class IonBailoutIterator : public IonFrameIterator
public:
IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *sp);
IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *sp);
IonBailoutIterator(const JitActivationIterator &activations, const IonFrameIterator &frame);
SnapshotOffset snapshotOffset() const {
JS_ASSERT(topIonScript_);
@ -157,6 +158,19 @@ uint32_t Bailout(BailoutStack *sp, BaselineBailoutInfo **info);
uint32_t InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
BaselineBailoutInfo **info);
struct ExceptionBailoutInfo
{
size_t frameNo;
jsbytecode *resumePC;
size_t numExprSlots;
};
// Called from the exception handler to enter a catch or finally block.
// Returns a BAILOUT_* error code.
uint32_t ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
const ExceptionBailoutInfo &excInfo,
BaselineBailoutInfo **bailoutInfo);
uint32_t FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo);
bool CheckFrequentBailouts(JSContext *cx, JSScript *script);

View File

@ -464,9 +464,16 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
HandleFunction fun, HandleScript script, IonScript *ionScript,
SnapshotIterator &iter, bool invalidate, BaselineStackBuilder &builder,
AutoValueVector &startFrameFormals, MutableHandleFunction nextCallee,
jsbytecode **callPC)
jsbytecode **callPC, const ExceptionBailoutInfo *excInfo)
{
uint32_t exprStackSlots = iter.slots() - (script->nfixed + CountArgSlots(script, fun));
// If excInfo is non-NULL, we are bailing out to a catch or finally block
// and this is the frame where we will resume. Usually the expression stack
// should be empty in this case but there can be iterators on the stack.
uint32_t exprStackSlots;
if (excInfo)
exprStackSlots = excInfo->numExprSlots;
else
exprStackSlots = iter.slots() - (script->nfixed + CountArgSlots(script, fun));
builder.resetFramePushed();
@ -641,10 +648,13 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
return false;
}
// Get the PC
jsbytecode *pc = script->code + iter.pcOffset();
// Get the pc. If we are handling an exception, resume at the pc of the
// catch or finally block.
jsbytecode *pc = excInfo ? excInfo->resumePC : script->code + iter.pcOffset();
bool resumeAfter = excInfo ? false : iter.resumeAfter();
JSOp op = JSOp(*pc);
bool resumeAfter = iter.resumeAfter();
JS_ASSERT_IF(excInfo, op == JSOP_ENTERBLOCK);
// Fixup inlined JSOP_FUNCALL, JSOP_FUNAPPLY, and accessors on the caller side.
// On the caller side this must represent like the function wasn't inlined.
@ -808,8 +818,9 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
BailoutKindString(bailoutKind));
#endif
// If this was the last inline frame, then unpacking is almost done.
if (!iter.moreFrames()) {
// If this was the last inline frame, or we are bailing out to a catch or
// finally block in this frame, then unpacking is almost done.
if (!iter.moreFrames() || excInfo) {
// Last frame, so PC for call to next frame is set to NULL.
*callPC = NULL;
@ -1167,7 +1178,8 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
uint32_t
ion::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter,
bool invalidate, BaselineBailoutInfo **bailoutInfo)
bool invalidate, BaselineBailoutInfo **bailoutInfo,
const ExceptionBailoutInfo *excInfo)
{
JS_ASSERT(bailoutInfo != NULL);
JS_ASSERT(*bailoutInfo == NULL);
@ -1214,10 +1226,17 @@ ion::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
IonSpew(IonSpew_BaselineBailouts, "Bailing to baseline %s:%u (IonScript=%p) (FrameType=%d)",
iter.script()->filename(), iter.script()->lineno, (void *) iter.ionScript(),
(int) prevFrameType);
if (excInfo)
IonSpew(IonSpew_BaselineBailouts, "Resuming in catch or finally block");
IonSpew(IonSpew_BaselineBailouts, " Reading from snapshot offset %u size %u",
iter.snapshotOffset(), iter.ionScript()->snapshotsSize());
iter.ionScript()->incNumBailouts();
if (excInfo)
iter.ionScript()->incNumExceptionBailouts();
else
iter.ionScript()->incNumBailouts();
iter.script()->updateBaselineOrIonRaw();
// Allocate buffer to hold stack replacement data.
@ -1242,7 +1261,7 @@ ion::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
IonSpew(IonSpew_BaselineBailouts, " Not constructing!");
IonSpew(IonSpew_BaselineBailouts, " Restoring frames:");
int frameNo = 0;
size_t frameNo = 0;
// Reconstruct baseline frames using the builder.
RootedScript caller(cx);
@ -1250,6 +1269,7 @@ ion::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
RootedFunction fun(cx, callee);
RootedScript scr(cx, iter.script());
AutoValueVector startFrameFormals(cx);
while (true) {
#if JS_TRACE_LOGGING
if (frameNo > 0) {
@ -1258,11 +1278,16 @@ ion::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
}
#endif
IonSpew(IonSpew_BaselineBailouts, " FrameNo %d", frameNo);
// If we are bailing out to a catch or finally block in this frame,
// pass excInfo to InitFromBailout and don't unpack any other frames.
bool handleException = (excInfo && excInfo->frameNo == frameNo);
jsbytecode *callPC = NULL;
RootedFunction nextCallee(cx, NULL);
if (!InitFromBailout(cx, caller, callerPC, fun, scr, iter.ionScript(),
snapIter, invalidate, builder, startFrameFormals,
&nextCallee, &callPC))
&nextCallee, &callPC, handleException ? excInfo : NULL))
{
return BAILOUT_RETURN_FATAL_ERROR;
}
@ -1272,6 +1297,9 @@ ion::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
break;
}
if (handleException)
break;
JS_ASSERT(nextCallee);
JS_ASSERT(callPC);
caller = scr;

View File

@ -27,7 +27,7 @@ BaselineCompiler::BaselineCompiler(JSContext *cx, HandleScript script)
bool
BaselineCompiler::init()
{
if (!analysis_.init())
if (!analysis_.init(cx))
return false;
if (!labels_.init(script->length))
@ -465,6 +465,13 @@ BaselineCompiler::emitUseCountIncrement()
masm.add32(Imm32(1), countReg);
masm.store32(countReg, useCountAddr);
// If this is a loop inside a catch or finally block, increment the use
// count but don't attempt OSR (Ion only compiles the try block).
if (analysis_.info(pc).loopEntryInCatchOrFinally) {
JS_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY);
return true;
}
Label skipCall;
uint32_t minUses = UsesBeforeIonRecompile(script, pc);

View File

@ -326,7 +326,8 @@ struct BaselineBailoutInfo
uint32_t
BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter,
bool invalidate, BaselineBailoutInfo **bailoutInfo);
bool invalidate, BaselineBailoutInfo **bailoutInfo,
const ExceptionBailoutInfo *exceptionInfo = NULL);
// Mark baseline scripts on the stack as active, so that they are not discarded
// during GC.

View File

@ -19,8 +19,25 @@ BytecodeAnalysis::BytecodeAnalysis(JSScript *script)
{
}
// Bytecode range containing only catch or finally code.
struct CatchFinallyRange
{
uint32_t start; // Inclusive.
uint32_t end; // Exclusive.
CatchFinallyRange(uint32_t start, uint32_t end)
: start(start), end(end)
{
JS_ASSERT(end > start);
}
bool contains(uint32_t offset) const {
return start <= offset && offset < end;
}
};
bool
BytecodeAnalysis::init()
BytecodeAnalysis::init(JSContext *cx)
{
if (!infos_.growByUninitialized(script_->length))
return false;
@ -31,6 +48,8 @@ BytecodeAnalysis::init()
mozilla::PodZero(infos_.begin(), infos_.length());
infos_[0].init(/*stackDepth=*/0);
Vector<CatchFinallyRange, 0, IonAllocPolicy> catchFinallyRanges;
for (jsbytecode *pc = script_->code; pc < end; pc += GetBytecodeLength(pc)) {
JSOp op = JSOp(*pc);
unsigned offset = pc - script_->code;
@ -59,7 +78,8 @@ BytecodeAnalysis::init()
// If stack depth exceeds max allowed by analysis, fail fast.
JS_ASSERT(stackDepth <= BytecodeInfo::MAX_STACK_DEPTH);
if (op == JSOP_TABLESWITCH) {
switch (op) {
case JSOP_TABLESWITCH: {
unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
int32_t low = GET_JUMP_OFFSET(pc2);
@ -78,7 +98,10 @@ BytecodeAnalysis::init()
}
pc2 += JUMP_OFFSET_LEN;
}
} else if (op == JSOP_TRY) {
break;
}
case JSOP_TRY: {
JSTryNote *tn = script_->trynotes()->vector;
JSTryNote *tnlimit = tn + script_->trynotes()->length;
for (; tn < tnlimit; tn++) {
@ -92,6 +115,37 @@ BytecodeAnalysis::init()
}
}
}
// Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
// jump over the catch/finally blocks.
jssrcnote *sn = js_GetSrcNote(cx, script_, pc);
JS_ASSERT(SN_TYPE(sn) == SRC_TRY);
jsbytecode *endOfTry = pc + js_GetSrcNoteOffset(sn, 0);
JS_ASSERT(JSOp(*endOfTry) == JSOP_GOTO);
jsbytecode *afterTry = endOfTry + GET_JUMP_OFFSET(endOfTry);
JS_ASSERT(afterTry > endOfTry);
// Pop CatchFinallyRanges that are no longer needed.
while (!catchFinallyRanges.empty() && catchFinallyRanges.back().end <= offset)
catchFinallyRanges.popBack();
CatchFinallyRange range(endOfTry - script_->code, afterTry - script_->code);
if (!catchFinallyRanges.append(range))
return false;
break;
}
case JSOP_LOOPENTRY:
for (size_t i = 0; i < catchFinallyRanges.length(); i++) {
if (catchFinallyRanges[i].contains(offset))
infos_[offset].loopEntryInCatchOrFinally = true;
}
break;
default:
break;
}
bool jump = IsJumpOpcode(op);

View File

@ -25,6 +25,9 @@ struct BytecodeInfo
bool jumpFallthrough : 1;
bool fallthrough : 1;
// If true, this is a JSOP_LOOPENTRY op inside a catch or finally block.
bool loopEntryInCatchOrFinally : 1;
void init(unsigned depth) {
JS_ASSERT(depth <= MAX_STACK_DEPTH);
JS_ASSERT_IF(initialized, stackDepth == depth);
@ -41,7 +44,7 @@ class BytecodeAnalysis
public:
explicit BytecodeAnalysis(JSScript *script);
bool init();
bool init(JSContext *cx);
BytecodeInfo &info(jsbytecode *pc) {
JS_ASSERT(infos_[pc - script_->code].initialized);

View File

@ -568,6 +568,7 @@ IonScript::IonScript()
invalidateEpilogueOffset_(0),
invalidateEpilogueDataOffset_(0),
numBailouts_(0),
numExceptionBailouts_(0),
hasUncompiledCallTarget_(false),
hasSPSInstrumentation_(false),
runtimeData_(0),
@ -995,8 +996,14 @@ OptimizeMIR(MIRGenerator *mir)
if (mir->shouldCancel("Dominator Tree"))
return false;
// This must occur before any code elimination.
if (!EliminatePhis(mir, graph, AggressiveObservability))
// Aggressive phi elimination must occur before any code elimination. If the
// script contains a try-statement, we only compiled the try block and not
// the catch or finally blocks, so in this case it's also invalid to use
// aggressive phi elimination.
Observability observability = graph.hasTryBlock()
? ConservativeObservability
: AggressiveObservability;
if (!EliminatePhis(mir, graph, observability))
return false;
IonSpewPass("Eliminate phis");
AssertGraphCoherency(graph);
@ -1380,6 +1387,10 @@ IonCompile(JSContext *cx, JSScript *script,
if (!script->ensureRanAnalysis(cx))
return AbortReason_Alloc;
// Try-finally is not yet supported.
if (script->analysis()->hasTryFinally())
return AbortReason_Disable;
LifoAlloc *alloc = cx->new_<LifoAlloc>(BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
if (!alloc)
return AbortReason_Alloc;

View File

@ -124,6 +124,15 @@ struct IonOptions
// Default: 10
uint32_t frequentBailoutThreshold;
// Number of exception bailouts (resuming into catch/finally block) before
// we invalidate and forbid Ion compilation.
//
// Default: 10
uint32_t exceptionBailoutThreshold;
// Whether Ion should compile try-catch statements.
bool compileTryCatch;
// How many actual arguments are accepted on the C stack.
//
// Default: 4,096
@ -205,6 +214,8 @@ struct IonOptions
usesBeforeInliningFactor(.125),
osrPcMismatchesBeforeRecompile(6000),
frequentBailoutThreshold(10),
exceptionBailoutThreshold(10),
compileTryCatch(false),
maxStackArgs(4096),
maxInlineDepth(3),
smallFunctionMaxInlineDepth(10),

View File

@ -56,6 +56,12 @@ ion::SplitCriticalEdges(MIRGraph &graph)
bool
ion::EliminateDeadResumePointOperands(MIRGenerator *mir, MIRGraph &graph)
{
// If we are compiling try blocks, locals and arguments may be observable
// from catch or finally blocks (which Ion does not compile). For now just
// disable the pass in this case.
if (graph.hasTryBlock())
return true;
for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
if (mir->shouldCancel("Eliminate Dead Resume Point Operands (main loop)"))
return false;

View File

@ -1162,6 +1162,9 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_IFEQ:
return jsop_ifeq(JSOP_IFEQ);
case JSOP_TRY:
return jsop_try();
case JSOP_CONDSWITCH:
return jsop_condswitch();
@ -1633,6 +1636,9 @@ IonBuilder::processCfgEntry(CFGState &state)
case CFGState::LABEL:
return processLabelEnd(state);
case CFGState::TRY:
return processTryEnd(state);
default:
MOZ_ASSUME_UNREACHABLE("unknown cfgstate");
}
@ -2175,6 +2181,30 @@ IonBuilder::processLabelEnd(CFGState &state)
return ControlStatus_Joined;
}
IonBuilder::ControlStatus
IonBuilder::processTryEnd(CFGState &state)
{
JS_ASSERT(state.state == CFGState::TRY);
if (!state.try_.successor) {
JS_ASSERT(!current);
return ControlStatus_Ended;
}
if (current) {
current->end(MGoto::New(state.try_.successor));
if (!state.try_.successor->addPredecessor(current))
return ControlStatus_Error;
}
// Start parsing the code after this try-catch statement.
setCurrentAndSpecializePhis(state.try_.successor);
graph().moveBlockToEnd(current);
pc = current->pc();
return ControlStatus_Joined;
}
IonBuilder::ControlStatus
IonBuilder::processBreak(JSOp op, jssrcnote *sn)
{
@ -2861,6 +2891,16 @@ IonBuilder::CFGState::Label(jsbytecode *exitpc)
return state;
}
IonBuilder::CFGState
IonBuilder::CFGState::Try(jsbytecode *exitpc, MBasicBlock *successor)
{
CFGState state;
state.state = TRY;
state.stopAt = exitpc;
state.try_.successor = successor;
return state;
}
IonBuilder::ControlStatus
IonBuilder::processCondSwitchCase(CFGState &state)
{
@ -3180,6 +3220,82 @@ IonBuilder::jsop_ifeq(JSOp op)
return true;
}
bool
IonBuilder::jsop_try()
{
JS_ASSERT(JSOp(*pc) == JSOP_TRY);
if (!js_IonOptions.compileTryCatch)
return abort("Try-catch support disabled");
// Try-finally is not yet supported.
JS_ASSERT(script()->analysis()->hasTryFinally());
graph().setHasTryBlock();
jssrcnote *sn = info().getNote(cx, pc);
JS_ASSERT(SN_TYPE(sn) == SRC_TRY);
// Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
// jump over the catch block.
jsbytecode *endpc = pc + js_GetSrcNoteOffset(sn, 0);
JS_ASSERT(JSOp(*endpc) == JSOP_GOTO);
JS_ASSERT(GetJumpOffset(endpc) > 0);
jsbytecode *afterTry = endpc + GetJumpOffset(endpc);
// If controlflow in the try body is terminated (by a return or throw
// statement), the code after the try-statement may still be reachable
// via the catch block (which we don't compile) and OSR can enter it.
// For example:
//
// try {
// throw 3;
// } catch(e) { }
//
// for (var i=0; i<1000; i++) {}
//
// To handle this, we create two blocks: one for the try block and one
// for the code following the try-catch statement. Both blocks are
// connected to the graph with an MTest instruction that always jumps to
// the try block. This ensures the successor block always has a predecessor
// and later passes will optimize this MTest to a no-op.
//
// If the code after the try block is unreachable (control flow in both the
// try and catch blocks is terminated), only create the try block, to avoid
// parsing unreachable code.
MBasicBlock *tryBlock = newBlock(current, GetNextPc(pc));
if (!tryBlock)
return false;
MBasicBlock *successor;
if (script()->analysis()->maybeCode(afterTry)) {
successor = newBlock(current, afterTry);
if (!successor)
return false;
// Add MTest(true, tryBlock, successorBlock).
MConstant *true_ = MConstant::New(BooleanValue(true));
current->add(true_);
current->end(MTest::New(true_, tryBlock, successor));
} else {
successor = NULL;
current->end(MGoto::New(tryBlock));
}
if (!cfgStack_.append(CFGState::Try(endpc, successor)))
return false;
// The baseline compiler should not attempt to enter the catch block
// via OSR.
JS_ASSERT(info().osrPc() < endpc || info().osrPc() >= afterTry);
// Start parsing the try block.
setCurrentAndSpecializePhis(tryBlock);
return true;
}
IonBuilder::ControlStatus
IonBuilder::processReturn(JSOp op)
{
@ -3220,6 +3336,35 @@ IonBuilder::processThrow()
{
MDefinition *def = current->pop();
if (graph().hasTryBlock()) {
// MThrow is not marked as effectful. This means when it throws and we
// are inside a try block, we could use an earlier resume point and this
// resume point may not be up-to-date, for example:
//
// (function() {
// try {
// var x = 1;
// foo(); // resume point
// x = 2;
// throw foo;
// } catch(e) {
// print(x);
// }
// ])();
//
// If we use the resume point after the call, this will print 1 instead
// of 2. To fix this, we create a resume point right before the MThrow.
//
// Note that this is not a problem for instructions other than MThrow
// because they are either marked as effectful (have their own resume
// point) or cannot throw a catchable exception.
MNop *ins = MNop::New();
current->add(ins);
if (!resumeAfter(ins))
return ControlStatus_Error;
}
MThrow *ins = MThrow::New(def);
current->end(ins);
@ -6372,9 +6517,7 @@ IonBuilder::jsop_getelem()
bool cacheable = obj->mightBeType(MIRType_Object) && !obj->mightBeType(MIRType_String) &&
(index->mightBeType(MIRType_Int32) || index->mightBeType(MIRType_String));
bool nonNativeGetElement =
script()->analysis()->getCode(pc).nonNativeGetElement ||
inspector->hasSeenNonNativeGetElement(pc);
bool nonNativeGetElement = inspector->hasSeenNonNativeGetElement(pc);
// Turn off cacheing if the element is int32 and we've seen non-native objects as the target
// of this getelem.

View File

@ -87,7 +87,8 @@ class IonBuilder : public MIRGenerator
COND_SWITCH_CASE, // switch() { case X: ... }
COND_SWITCH_BODY, // switch() { case ...: X }
AND_OR, // && x, || x
LABEL // label: x
LABEL, // label: x
TRY // try { x } catch(e) { }
};
State state; // Current state of this control structure.
@ -169,6 +170,9 @@ class IonBuilder : public MIRGenerator
struct {
DeferredEdge *breaks;
} label;
struct {
MBasicBlock *successor;
} try_;
};
inline bool isLoop() const {
@ -192,6 +196,7 @@ class IonBuilder : public MIRGenerator
static CFGState TableSwitch(jsbytecode *exitpc, MTableSwitch *ins);
static CFGState CondSwitch(jsbytecode *exitpc, jsbytecode *defaultTarget);
static CFGState Label(jsbytecode *exitpc);
static CFGState Try(jsbytecode *exitpc, MBasicBlock *successor);
};
static int CmpSuccessors(const void *a, const void *b);
@ -249,6 +254,7 @@ class IonBuilder : public MIRGenerator
ControlStatus processSwitchEnd(DeferredEdge *breaks, jsbytecode *exitpc);
ControlStatus processAndOrEnd(CFGState &state);
ControlStatus processLabelEnd(CFGState &state);
ControlStatus processTryEnd(CFGState &state);
ControlStatus processReturn(JSOp op);
ControlStatus processThrow();
ControlStatus processContinue(JSOp op);
@ -381,6 +387,7 @@ class IonBuilder : public MIRGenerator
bool jsop_call(uint32_t argc, bool constructing);
bool jsop_eval(uint32_t argc);
bool jsop_ifeq(JSOp op);
bool jsop_try();
bool jsop_label();
bool jsop_condswitch();
bool jsop_andor(JSOp op);

View File

@ -192,6 +192,10 @@ struct IonScript
// Number of times this script bailed out without invalidation.
uint32_t numBailouts_;
// Number of times this scripted bailed out to enter a catch or
// finally block.
uint32_t numExceptionBailouts_;
// Flag set when it is likely that one of our (transitive) call
// targets is not compiled. Used in ForkJoin.cpp to decide when
// we should add call targets to the worklist.
@ -410,6 +414,12 @@ struct IonScript
bool bailoutExpected() const {
return numBailouts_ > 0;
}
void incNumExceptionBailouts() {
numExceptionBailouts_++;
}
uint32_t numExceptionBailouts() const {
return numExceptionBailouts_;
}
void setHasUncompiledCallTarget() {
hasUncompiledCallTarget_ = true;
}

View File

@ -480,6 +480,15 @@ class InlineFrameIteratorMaybeGC
void resetOn(const IonFrameIterator *iter);
const IonFrameIterator &frame() const {
return *frame_;
}
// Inline frame number, 0 for the outermost (non-inlined) frame.
size_t frameNo() const {
return start_.frameCount() - framesRead_;
}
private:
InlineFrameIteratorMaybeGC() MOZ_DELETE;
InlineFrameIteratorMaybeGC(const InlineFrameIteratorMaybeGC &iter) MOZ_DELETE;

View File

@ -350,7 +350,8 @@ CloseLiveIterator(JSContext *cx, const InlineFrameIterator &frame, uint32_t loca
}
static void
CloseLiveIterators(JSContext *cx, const InlineFrameIterator &frame)
HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe,
bool *overrecursed)
{
RootedScript script(cx, frame.script());
jsbytecode *pc = frame.pc();
@ -368,20 +369,63 @@ CloseLiveIterators(JSContext *cx, const InlineFrameIterator &frame)
if (pcOffset >= tn->start + tn->length)
continue;
if (tn->kind != JSTRY_ITER)
continue;
switch (tn->kind) {
case JSTRY_ITER: {
JS_ASSERT(JSOp(*(script->main() + tn->start + tn->length)) == JSOP_ENDITER);
JS_ASSERT(tn->stackDepth > 0);
JS_ASSERT(JSOp(*(script->main() + tn->start + tn->length)) == JSOP_ENDITER);
JS_ASSERT(tn->stackDepth > 0);
uint32_t localSlot = tn->stackDepth;
CloseLiveIterator(cx, frame, localSlot);
break;
}
uint32_t localSlot = tn->stackDepth;
CloseLiveIterator(cx, frame, localSlot);
case JSTRY_LOOP:
break;
case JSTRY_CATCH:
if (cx->isExceptionPending()) {
// Bailout at the start of the catch block.
jsbytecode *catchPC = script->main() + tn->start + tn->length;
ExceptionBailoutInfo excInfo;
excInfo.frameNo = frame.frameNo();
excInfo.resumePC = catchPC;
excInfo.numExprSlots = tn->stackDepth;
BaselineBailoutInfo *info = NULL;
uint32_t retval = ExceptionHandlerBailout(cx, frame, excInfo, &info);
if (retval == BAILOUT_RETURN_OK) {
JS_ASSERT(info);
rfe->kind = ResumeFromException::RESUME_BAILOUT;
rfe->target = cx->runtime()->ionRuntime()->getBailoutTail()->raw();
rfe->bailoutInfo = info;
return;
}
// Bailout failed. If there was a fatal error, clear the
// exception to turn this into an uncatchable error. If the
// overrecursion check failed, continue popping all inline
// frames and have the caller report an overrecursion error.
JS_ASSERT(!info);
cx->clearPendingException();
if (retval == BAILOUT_RETURN_OVERRECURSED)
*overrecursed = true;
else
JS_ASSERT(retval == BAILOUT_RETURN_FATAL_ERROR);
}
break;
default:
MOZ_ASSUME_UNREACHABLE("Unexpected try note");
}
}
}
static void
HandleException(JSContext *cx, const IonFrameIterator &frame, ResumeFromException *rfe,
bool *calledDebugEpilogue)
HandleExceptionBaseline(JSContext *cx, const IonFrameIterator &frame, ResumeFromException *rfe,
bool *calledDebugEpilogue)
{
JS_ASSERT(frame.isBaselineJS());
JS_ASSERT(!*calledDebugEpilogue);
@ -511,12 +555,15 @@ HandleException(ResumeFromException *rfe)
IonFrameIterator iter(cx->mainThread().ionTop);
while (!iter.isEntry()) {
bool overrecursed = false;
if (iter.isOptimizedJS()) {
// Search each inlined frame for live iterator objects, and close
// them.
InlineFrameIterator frames(cx, &iter);
for (;;) {
CloseLiveIterators(cx, frames);
HandleExceptionIon(cx, frames, rfe, &overrecursed);
if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
return;
// When profiling, each frame popped needs a notification that
// the function has exited, so invoke the probe that a function
@ -536,7 +583,7 @@ HandleException(ResumeFromException *rfe)
// It's invalid to call DebugEpilogue twice for the same frame.
bool calledDebugEpilogue = false;
HandleException(cx, iter, rfe, &calledDebugEpilogue);
HandleExceptionBaseline(cx, iter, rfe, &calledDebugEpilogue);
if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
return;
@ -575,6 +622,11 @@ HandleException(ResumeFromException *rfe)
EnsureExitFrame(current);
cx->mainThread().ionTop = (uint8_t *)current;
}
if (overrecursed) {
// We hit an overrecursion error during bailout. Report it now.
js_ReportOverRecursed(cx);
}
}
rfe->stackPointer = iter.fp();

View File

@ -255,6 +255,8 @@ class FrameSizeClass
}
};
struct BaselineBailoutInfo;
// Data needed to recover from an exception.
struct ResumeFromException
{
@ -262,6 +264,7 @@ struct ResumeFromException
static const uint32_t RESUME_CATCH = 1;
static const uint32_t RESUME_FINALLY = 2;
static const uint32_t RESUME_FORCED_RETURN = 3;
static const uint32_t RESUME_BAILOUT = 4;
uint8_t *framePointer;
uint8_t *stackPointer;
@ -270,6 +273,8 @@ struct ResumeFromException
// Value to push when resuming into a |finally| block.
Value exception;
BaselineBailoutInfo *bailoutInfo;
};
void HandleException(ResumeFromException *rfe);

View File

@ -545,6 +545,7 @@ class MIRGraph
Vector<JSScript *, 4, IonAllocPolicy> scripts_;
size_t numBlocks_;
bool hasTryBlock_;
public:
MIRGraph(TempAllocator *alloc)
@ -554,7 +555,8 @@ class MIRGraph
idGen_(0),
osrBlock_(NULL),
osrStart_(NULL),
numBlocks_(0)
numBlocks_(0),
hasTryBlock_(false)
{ }
template <typename T>
@ -677,6 +679,13 @@ class MIRGraph
return scripts_.begin();
}
bool hasTryBlock() const {
return hasTryBlock_;
}
void setHasTryBlock() {
hasTryBlock_ = true;
}
// The per-thread context. So as not to modify the calling convention for
// parallel code, we obtain the current slice from thread-local storage.
// This helper method will lazilly insert an MForkJoinSlice instruction in

View File

@ -9,6 +9,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"
#include "ion/Bailouts.h"
#include "ion/BaselineFrame.h"
#include "ion/MoveEmitter.h"
@ -3330,12 +3331,14 @@ MacroAssemblerARMCompat::handleFailureWithHandlerTail()
Label catch_;
Label finally;
Label return_;
Label bailout;
ma_ldr(Operand(sp, offsetof(ResumeFromException, kind)), r0);
branch32(Assembler::Equal, r0, Imm32(ResumeFromException::RESUME_ENTRY_FRAME), &entryFrame);
branch32(Assembler::Equal, r0, Imm32(ResumeFromException::RESUME_CATCH), &catch_);
branch32(Assembler::Equal, r0, Imm32(ResumeFromException::RESUME_FINALLY), &finally);
branch32(Assembler::Equal, r0, Imm32(ResumeFromException::RESUME_FORCED_RETURN), &return_);
branch32(Assembler::Equal, r0, Imm32(ResumeFromException::RESUME_BAILOUT), &bailout);
breakpoint(); // Invalid kind.
@ -3380,6 +3383,14 @@ MacroAssemblerARMCompat::handleFailureWithHandlerTail()
ma_mov(r11, sp);
pop(r11);
ret();
// If we are bailing out to baseline to handle an exception, jump to
// the bailout tail stub.
bind(&bailout);
ma_ldr(Operand(sp, offsetof(ResumeFromException, bailoutInfo)), r2);
ma_mov(Imm32(BAILOUT_RETURN_OK), r0);
ma_ldr(Operand(sp, offsetof(ResumeFromException, target)), r1);
jump(r1);
}
Assembler::Condition

View File

@ -376,9 +376,10 @@ CodeGeneratorX86Shared::visitMinMaxD(LMinMaxD *ins)
{
FloatRegister first = ToFloatRegister(ins->first());
FloatRegister second = ToFloatRegister(ins->second());
#ifdef DEBUG
FloatRegister output = ToFloatRegister(ins->output());
JS_ASSERT(first == output);
#endif
Label done, nan, minMaxInst;

View File

@ -8,6 +8,7 @@
#include "mozilla/Casting.h"
#include "ion/Bailouts.h"
#include "ion/BaselineFrame.h"
#include "ion/IonFrames.h"
#include "ion/MoveEmitter.h"
@ -253,12 +254,14 @@ MacroAssemblerX64::handleFailureWithHandlerTail()
Label catch_;
Label finally;
Label return_;
Label bailout;
loadPtr(Address(rsp, offsetof(ResumeFromException, kind)), rax);
branch32(Assembler::Equal, rax, Imm32(ResumeFromException::RESUME_ENTRY_FRAME), &entryFrame);
branch32(Assembler::Equal, rax, Imm32(ResumeFromException::RESUME_CATCH), &catch_);
branch32(Assembler::Equal, rax, Imm32(ResumeFromException::RESUME_FINALLY), &finally);
branch32(Assembler::Equal, rax, Imm32(ResumeFromException::RESUME_FORCED_RETURN), &return_);
branch32(Assembler::Equal, rax, Imm32(ResumeFromException::RESUME_BAILOUT), &bailout);
breakpoint(); // Invalid kind.
@ -300,6 +303,13 @@ MacroAssemblerX64::handleFailureWithHandlerTail()
movq(rbp, rsp);
pop(rbp);
ret();
// If we are bailing out to baseline to handle an exception, jump to
// the bailout tail stub.
bind(&bailout);
movq(Operand(esp, offsetof(ResumeFromException, bailoutInfo)), r9);
movl(Imm32(BAILOUT_RETURN_OK), rax);
jmp(Operand(rsp, offsetof(ResumeFromException, target)));
}
Assembler::Condition

View File

@ -8,6 +8,7 @@
#include "mozilla/Casting.h"
#include "ion/Bailouts.h"
#include "ion/BaselineFrame.h"
#include "ion/IonFrames.h"
#include "ion/MoveEmitter.h"
@ -225,12 +226,14 @@ MacroAssemblerX86::handleFailureWithHandlerTail()
Label catch_;
Label finally;
Label return_;
Label bailout;
loadPtr(Address(esp, offsetof(ResumeFromException, kind)), eax);
branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_ENTRY_FRAME), &entryFrame);
branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_CATCH), &catch_);
branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_FINALLY), &finally);
branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_FORCED_RETURN), &return_);
branch32(Assembler::Equal, eax, Imm32(ResumeFromException::RESUME_BAILOUT), &bailout);
breakpoint(); // Invalid kind.
@ -272,6 +275,13 @@ MacroAssemblerX86::handleFailureWithHandlerTail()
movl(ebp, esp);
pop(ebp);
ret();
// If we are bailing out to baseline to handle an exception, jump to
// the bailout tail stub.
bind(&bailout);
movl(Operand(esp, offsetof(ResumeFromException, bailoutInfo)), ecx);
movl(Imm32(BAILOUT_RETURN_OK), eax);
jmp(Operand(esp, offsetof(ResumeFromException, target)));
}
void

View File

@ -0,0 +1,12 @@
function F() {
try {
var T = {};
throw 12;
} catch (e) {
// Don't throw.
T.x = 5;
}
}
F();
F();
F();

View File

@ -0,0 +1,14 @@
// Control flow does not reach end of try block, code after try statement is
// reachable by catch block.
function f() {
try {
throw 3;
} catch(e) {
}
var res = 0;
for (var i=0; i<40; i++)
res += 2;
return res;
}
assertEq(f(), 80);

View File

@ -0,0 +1,27 @@
// Don't fail if code after try statement is unreachable.
function f() {
try {
throw 1;
} catch(e) {
throw 5;
}
// Unreachable.
assertEq(0, 2);
var res = 0;
for (var i=0; i<10; i++)
res += 2;
return res;
}
var c = 0;
for (var i=0; i<5; i++) {
try {
f();
assertEq(0, 1);
} catch(e) {
c += e;
}
}
assertEq(c, 25);

View File

@ -0,0 +1,15 @@
// Entering catch blocks via OSR is not possible (because the catch block
// is not compiled by Ion). Don't crash.
function f() {
var res = 0;
try {
throw 1;
} catch(e) {
for (var i=0; i<10; i++) {
res += 3;
}
}
assertEq(res, 30);
}
f();

View File

@ -104,8 +104,6 @@ class Bytecode
* hints about the script for use during compilation.
*/
bool arrayWriteHole: 1; /* SETELEM which has written to an array hole. */
bool getStringElement:1; /* GETELEM which has accessed string properties. */
bool nonNativeGetElement:1; /* GETELEM on a non-native, non-array object. */
bool accessGetter: 1; /* Property read on a shape with a getter hook. */
/* Stack depth before this opcode. */

View File

@ -433,6 +433,10 @@ class AutoLockForExclusiveAccess
AutoLockForExclusiveAccess(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
~AutoLockForExclusiveAccess() {
// An empty destructor is needed to avoid warnings from clang about
// unused local variables of this type.
}
#endif // JS_THREADSAFE
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER

View File

@ -507,7 +507,7 @@ Class JSFunction::class_ = {
fun_trace
};
JS_FRIEND_DATA(Class* const) js::FunctionClassPtr = &JSFunction::class_;
Class* const js::FunctionClassPtr = &JSFunction::class_;
/* Find the body of a function (not including braces). */
static bool

View File

@ -80,7 +80,7 @@ Class JSObject::class_ = {
JS_ConvertStub
};
JS_FRIEND_DATA(Class* const) js::ObjectClassPtr = &JSObject::class_;
Class* const js::ObjectClassPtr = &JSObject::class_;
JS_FRIEND_API(JSObject *)
JS_ObjectToInnerObject(JSContext *cx, JSObject *objArg)

View File

@ -3133,7 +3133,7 @@ Class js::ObjectProxyObject::class_ = {
}
};
JS_FRIEND_DATA(Class* const) js::ObjectProxyClassPtr = &ObjectProxyObject::class_;
Class* const js::ObjectProxyClassPtr = &ObjectProxyObject::class_;
Class js::OuterWindowProxyObject::class_ = {
"Proxy",
@ -3192,7 +3192,7 @@ Class js::OuterWindowProxyObject::class_ = {
}
};
JS_FRIEND_DATA(Class* const) js::OuterWindowProxyClassPtr = &OuterWindowProxyObject::class_;
Class* const js::OuterWindowProxyClassPtr = &OuterWindowProxyObject::class_;
static bool
proxy_Call(JSContext *cx, unsigned argc, Value *vp)
@ -3263,7 +3263,7 @@ Class js::FunctionProxyObject::class_ = {
}
};
JS_FRIEND_DATA(Class* const) js::FunctionProxyClassPtr = &FunctionProxyObject::class_;
Class* const js::FunctionProxyClassPtr = &FunctionProxyObject::class_;
/* static */ ProxyObject *
ProxyObject::New(JSContext *cx, BaseProxyHandler *handler, HandleValue priv, TaggedProto proto_,

View File

@ -2009,6 +2009,12 @@ JSScript::isShortRunning()
!analysis()->hasFunctionCalls();
}
js::GlobalObject&
JSScript::uninlinedGlobal() const
{
return global();
}
bool
JSScript::enclosingScriptsCompiledSuccessfully() const
{

View File

@ -809,6 +809,7 @@ class JSScript : public js::gc::Cell
inline void clearPropertyReadTypes();
inline js::GlobalObject &global() const;
js::GlobalObject &uninlinedGlobal() const;
/* See StaticScopeIter comment. */
JSObject *enclosingStaticScope() const {

View File

@ -289,8 +289,10 @@ class AutoUnlockWorkerThreadState
/* Pause any threads that are running jobs off thread during GC activity. */
class AutoPauseWorkersForGC
{
#ifdef JS_WORKER_THREADS
JSRuntime *runtime;
bool needsUnpause;
#endif
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
public:

View File

@ -5141,6 +5141,9 @@ ProcessArgs(JSContext *cx, JSObject *obj_, OptionParser *op)
if (op->getBoolOption("ion-eager"))
ion::js_IonOptions.setEagerCompilation();
if (op->getBoolOption("ion-compile-try-catch"))
ion::js_IonOptions.compileTryCatch = true;
#ifdef JS_THREADSAFE
if (const char *str = op->getStringOption("ion-parallel-compile")) {
if (strcmp(str, "on") == 0) {
@ -5386,6 +5389,7 @@ main(int argc, char **argv, char **envp)
" backtracking: Priority based backtracking register allocation\n"
" stupid: Simple block local register allocation")
|| !op.addBoolOption('\0', "ion-eager", "Always ion-compile methods (implies --baseline-eager)")
|| !op.addBoolOption('\0', "ion-compile-try-catch", "Ion-compile try-catch statements")
#ifdef JS_THREADSAFE
|| !op.addStringOption('\0', "ion-parallel-compile", "on/off",
"Compile scripts off thread (default: off)")

View File

@ -677,7 +677,7 @@ void
Debugger::onNewScript(JSContext *cx, HandleScript script, GlobalObject *compileAndGoGlobal)
{
JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal);
JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal == &script->global());
JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal == &script->uninlinedGlobal());
// We early return in slowPathOnNewScript for self-hosted scripts, so we can
// ignore those in our assertion here.
JS_ASSERT_IF(!script->compartment()->options().invisibleToDebugger &&

View File

@ -357,20 +357,8 @@ GetObjectElementOperation(JSContext *cx, JSOp op, JSObject *objArg, bool wasObje
HandleValue rref, MutableHandleValue res)
{
do {
// Don't call GetPcScript (needed for analysis) from inside Ion since it's expensive.
bool analyze = cx->currentlyRunningInInterpreter();
uint32_t index;
if (IsDefinitelyIndex(rref, &index)) {
if (analyze && !objArg->isNative() && !objArg->is<TypedArrayObject>()) {
JSScript *script = NULL;
jsbytecode *pc = NULL;
types::TypeScript::GetPcScript(cx, &script, &pc);
if (script->hasAnalysis())
script->analysis()->getCode(pc).nonNativeGetElement = true;
}
if (JSObject::getElementNoGC(cx, objArg, objArg, index, res.address()))
break;
@ -381,22 +369,6 @@ GetObjectElementOperation(JSContext *cx, JSOp op, JSObject *objArg, bool wasObje
break;
}
if (analyze) {
JSScript *script = NULL;
jsbytecode *pc = NULL;
types::TypeScript::GetPcScript(cx, &script, &pc);
if (script->hasAnalysis()) {
script->analysis()->getCode(pc).getStringElement = true;
if (!objArg->is<ArrayObject>() && !objArg->isNative() &&
!objArg->is<TypedArrayObject>())
{
script->analysis()->getCode(pc).nonNativeGetElement = true;
}
}
}
if (ValueMightBeSpecial(rref)) {
RootedObject obj(cx, objArg);
Rooted<SpecialId> special(cx);

View File

@ -1263,17 +1263,10 @@ SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, con
uint32_t length = obj->getDenseInitializedLength();
int32_t i = JSID_TO_INT(id);
if ((uint32_t)i >= length) {
// In an Ion activation, GetPcScript won't work. For non-baseline activations,
// that's ok, because optimized ion doesn't generate analysis info. However,
// baseline must generate this information, so it passes the script and pc in
// as arguments.
if (script || cx->currentlyRunningInInterpreter()) {
JS_ASSERT(!!script == !!pc);
if (!script)
types::TypeScript::GetPcScript(cx, script.address(), &pc);
if (script->hasAnalysis())
script->analysis()->getCode(pc).arrayWriteHole = true;
// Annotate script if provided with information (e.g. baseline)
if (script && script->hasAnalysis()) {
JS_ASSERT(pc);
script->analysis()->getCode(pc).arrayWriteHole = true;
}
}
}

View File

@ -186,7 +186,10 @@ ThreadPoolWorker::terminate()
// them down when requested.
ThreadPool::ThreadPool(JSRuntime *rt)
: runtime_(rt),
:
#if defined(JS_THREADSAFE) || defined(DEBUG)
runtime_(rt),
#endif
numWorkers_(0), // updated during init()
nextId_(0)
{

View File

@ -70,7 +70,9 @@ class ThreadPool
friend class ThreadPoolWorker;
// Initialized at startup only:
#if defined(JS_THREADSAFE) || defined(DEBUG)
JSRuntime *const runtime_;
#endif
js::Vector<ThreadPoolWorker*, 8, SystemAllocPolicy> workers_;
// Number of workers we will start, when we actually start them

View File

@ -457,7 +457,7 @@ inline bool IsDOMProxy(JSObject *obj)
typedef JSObject*
(*DefineInterface)(JSContext *cx, JS::Handle<JSObject*> global,
JS::Handle<jsid> id, bool *enabled);
JS::Handle<jsid> id, bool defineOnGlobal);
typedef JSObject*
(*ConstructNavigatorProperty)(JSContext *cx, JS::Handle<JSObject*> naviObj);

View File

@ -682,7 +682,35 @@ Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue) const
return;
}
AppendValueToString(eCSSProperty_text_decoration_line, aValue);
const nsCSSValue *textBlink =
data->ValueFor(eCSSProperty_text_blink);
const nsCSSValue *decorationLine =
data->ValueFor(eCSSProperty_text_decoration_line);
NS_ABORT_IF_FALSE(textBlink->GetUnit() == eCSSUnit_Enumerated,
nsPrintfCString("bad text-blink unit %d",
textBlink->GetUnit()).get());
NS_ABORT_IF_FALSE(decorationLine->GetUnit() == eCSSUnit_Enumerated,
nsPrintfCString("bad text-decoration-line unit %d",
decorationLine->GetUnit()).get());
bool blinkNone = (textBlink->GetIntValue() == NS_STYLE_TEXT_BLINK_NONE);
bool lineNone =
(decorationLine->GetIntValue() == NS_STYLE_TEXT_DECORATION_LINE_NONE);
if (blinkNone && lineNone) {
AppendValueToString(eCSSProperty_text_decoration_line, aValue);
} else {
if (!blinkNone) {
AppendValueToString(eCSSProperty_text_blink, aValue);
}
if (!lineNone) {
if (!aValue.IsEmpty()) {
aValue.Append(PRUnichar(' '));
}
AppendValueToString(eCSSProperty_text_decoration_line, aValue);
}
}
break;
}
case eCSSProperty_transition: {

View File

@ -9555,7 +9555,7 @@ CSSParserImpl::ParseTextDecoration()
return false;
}
nsCSSValue line, style, color;
nsCSSValue blink, line, style, color;
switch (value.GetUnit()) {
case eCSSUnit_Enumerated: {
// We shouldn't accept decoration line style and color via
@ -9567,6 +9567,7 @@ CSSParserImpl::ParseTextDecoration()
int32_t intValue = value.GetIntValue();
if (intValue == eDecorationNone) {
blink.SetIntValue(NS_STYLE_TEXT_BLINK_NONE, eCSSUnit_Enumerated);
line.SetIntValue(NS_STYLE_TEXT_DECORATION_LINE_NONE,
eCSSUnit_Enumerated);
break;
@ -9588,14 +9589,18 @@ CSSParserImpl::ParseTextDecoration()
intValue |= newValue;
}
line.SetIntValue(intValue, eCSSUnit_Enumerated);
blink.SetIntValue((intValue & eDecorationBlink) != 0 ?
NS_STYLE_TEXT_BLINK_BLINK : NS_STYLE_TEXT_BLINK_NONE,
eCSSUnit_Enumerated);
line.SetIntValue((intValue & ~eDecorationBlink), eCSSUnit_Enumerated);
break;
}
default:
line = color = style = value;
blink = line = color = style = value;
break;
}
AppendValue(eCSSProperty_text_blink, blink);
AppendValue(eCSSProperty_text_decoration_line, line);
AppendValue(eCSSProperty_text_decoration_color, color);
AppendValue(eCSSProperty_text_decoration_style, style);
@ -9613,7 +9618,7 @@ CSSParserImpl::ParseTextDecorationLine(nsCSSValue& aValue)
// look for more keywords
nsCSSValue keyword;
int32_t index;
for (index = 0; index < 3; index++) {
for (index = 0; index < 2; index++) {
if (ParseEnum(keyword, nsCSSProps::kTextDecorationLineKTable)) {
int32_t newValue = keyword.GetIntValue();
if (newValue == NS_STYLE_TEXT_DECORATION_LINE_NONE ||

View File

@ -2745,6 +2745,18 @@ CSS_PROP_SHORTHAND(
TextDecoration,
CSS_PROPERTY_PARSE_FUNCTION,
"")
CSS_PROP_TEXTRESET(
-moz-text-blink,
text_blink,
CSS_PROP_DOMPROP_PREFIXED(TextBlink),
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
"",
VARIANT_HK,
kTextBlinkKTable,
offsetof(nsStyleTextReset, mTextBlink),
eStyleAnimType_EnumU8)
CSS_PROP_TEXTRESET(
-moz-text-decoration-color,
text_decoration_color,

View File

@ -1435,12 +1435,17 @@ const int32_t nsCSSProps::kTextAlignLastKTable[] = {
eCSSKeyword_UNKNOWN,-1
};
const int32_t nsCSSProps::kTextBlinkKTable[] = {
eCSSKeyword_none, NS_STYLE_TEXT_BLINK_NONE,
eCSSKeyword_blink, NS_STYLE_TEXT_BLINK_BLINK,
eCSSKeyword_UNKNOWN,-1
};
const int32_t nsCSSProps::kTextDecorationLineKTable[] = {
eCSSKeyword_none, NS_STYLE_TEXT_DECORATION_LINE_NONE,
eCSSKeyword_underline, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
eCSSKeyword_overline, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE,
eCSSKeyword_line_through, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
eCSSKeyword_blink, NS_STYLE_TEXT_DECORATION_LINE_BLINK,
eCSSKeyword__moz_anchor_decoration, NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS,
eCSSKeyword_UNKNOWN,-1
};
@ -2359,6 +2364,7 @@ static const nsCSSProperty gPaddingEndSubpropTable[] = {
};
static const nsCSSProperty gTextDecorationSubpropTable[] = {
eCSSProperty_text_blink,
eCSSProperty_text_decoration_color,
eCSSProperty_text_decoration_line,
eCSSProperty_text_decoration_style,

View File

@ -529,6 +529,7 @@ public:
static const int32_t kTableLayoutKTable[];
static const int32_t kTextAlignKTable[];
static const int32_t kTextAlignLastKTable[];
static const int32_t kTextBlinkKTable[];
static const int32_t kTextDecorationLineKTable[];
static const int32_t kTextDecorationStyleKTable[];
static const int32_t kTextOverflowKTable[];

View File

@ -2644,6 +2644,18 @@ nsComputedDOMStyle::DoGetTextAlignLast()
return val;
}
CSSValue*
nsComputedDOMStyle::DoGetMozTextBlink()
{
nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mTextBlink,
nsCSSProps::kTextBlinkKTable));
return val;
}
CSSValue*
nsComputedDOMStyle::DoGetTextDecoration()
{
@ -2674,14 +2686,25 @@ nsComputedDOMStyle::DoGetTextDecoration()
// don't want these to appear in the computed style.
line &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS |
NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
uint8_t blink = textReset->mTextBlink;
if (line == NS_STYLE_TEXT_DECORATION_LINE_NONE) {
if (blink == NS_STYLE_TEXT_BLINK_NONE &&
line == NS_STYLE_TEXT_DECORATION_LINE_NONE) {
val->SetIdent(eCSSKeyword_none);
} else {
nsAutoString str;
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
line, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
NS_STYLE_TEXT_DECORATION_LINE_BLINK, str);
if (line != NS_STYLE_TEXT_DECORATION_LINE_NONE) {
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
line, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, str);
}
if (blink != NS_STYLE_TEXT_BLINK_NONE) {
if (!str.IsEmpty()) {
str.Append(PRUnichar(' '));
}
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_blink, blink,
NS_STYLE_TEXT_BLINK_BLINK, NS_STYLE_TEXT_BLINK_BLINK, str);
}
val->SetString(str);
}
@ -2722,7 +2745,7 @@ nsComputedDOMStyle::DoGetTextDecorationLine()
NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
intValue, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
NS_STYLE_TEXT_DECORATION_LINE_BLINK, decorationLineString);
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, decorationLineString);
val->SetString(decorationLineString);
}
@ -5117,6 +5140,7 @@ nsComputedDOMStyle::GetQueryablePropertyMap(uint32_t* aLength)
COMPUTED_STYLE_MAP_ENTRY(stack_sizing, StackSizing),
COMPUTED_STYLE_MAP_ENTRY(_moz_tab_size, TabSize),
COMPUTED_STYLE_MAP_ENTRY(text_align_last, TextAlignLast),
COMPUTED_STYLE_MAP_ENTRY(text_blink, MozTextBlink),
COMPUTED_STYLE_MAP_ENTRY(text_decoration_color, TextDecorationColor),
COMPUTED_STYLE_MAP_ENTRY(text_decoration_line, TextDecorationLine),
COMPUTED_STYLE_MAP_ENTRY(text_decoration_style, TextDecorationStyle),

View File

@ -307,6 +307,7 @@ private:
mozilla::dom::CSSValue* DoGetLineHeight();
mozilla::dom::CSSValue* DoGetTextAlign();
mozilla::dom::CSSValue* DoGetTextAlignLast();
mozilla::dom::CSSValue* DoGetMozTextBlink();
mozilla::dom::CSSValue* DoGetTextDecoration();
mozilla::dom::CSSValue* DoGetTextDecorationColor();
mozilla::dom::CSSValue* DoGetTextDecorationLine();

View File

@ -4012,6 +4012,11 @@ nsRuleNode::ComputeTextResetData(void* aStartStruct,
}
}
// text-blink: enum, inherit, initial
SetDiscrete(*aRuleData->ValueForTextBlink(), text->mTextBlink,
canStoreInRuleTree, SETDSC_ENUMERATED, parentText->mTextBlink,
NS_STYLE_TEXT_BLINK_NONE, 0, 0, 0, 0);
// text-decoration-line: enum (bit field), inherit, initial
const nsCSSValue* decorationLineValue =
aRuleData->ValueForTextDecorationLine();

View File

@ -659,6 +659,10 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
// Note: make sure that the largest NS_STYLE_TEXT_ALIGN_* value is smaller than
// the smallest NS_STYLE_VERTICAL_ALIGN_* value below!
// See nsStyleText
#define NS_STYLE_TEXT_BLINK_NONE 0
#define NS_STYLE_TEXT_BLINK_BLINK 1
// See nsStyleText, nsStyleFont
#define NS_STYLE_TEXT_DECORATION_LINE_NONE 0
#define NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE NS_FONT_DECORATION_UNDERLINE

View File

@ -2826,6 +2826,7 @@ nsStyleTextReset::nsStyleTextReset(void)
{
MOZ_COUNT_CTOR(nsStyleTextReset);
mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE, eStyleUnit_Enumerated);
mTextBlink = NS_STYLE_TEXT_BLINK_NONE;
mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
mTextDecorationColor = NS_RGB(0,0,0);
mTextDecorationStyle =

View File

@ -1281,6 +1281,7 @@ struct nsStyleTextReset {
nsStyleCoord mVerticalAlign; // [reset] coord, percent, calc, enum (see nsStyleConsts.h)
nsStyleTextOverflow mTextOverflow; // [reset] enum, string
uint8_t mTextBlink; // [reset] see nsStyleConsts.h
uint8_t mTextDecorationLine; // [reset] see nsStyleConsts.h
uint8_t mUnicodeBidi; // [reset] see nsStyleConsts.h
protected:

View File

@ -3089,11 +3089,19 @@ var gCSSProperties = {
other_values: [ "center", "justify", "start", "end", "left", "right" ],
invalid_values: []
},
"-moz-text-blink": {
domProp: "MozTextBlink",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [ "blink" ],
invalid_values: [ "underline", "overline", "line-through", "none underline", "underline blink", "blink underline" ]
},
"text-decoration": {
domProp: "textDecoration",
inherited: false,
type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
subproperties: [ "-moz-text-decoration-color", "-moz-text-decoration-line", "-moz-text-decoration-style" ],
subproperties: [ "-moz-text-blink", "-moz-text-decoration-color", "-moz-text-decoration-line", "-moz-text-decoration-style" ],
initial_values: [ "none" ],
other_values: [ "underline", "overline", "line-through", "blink", "blink line-through underline", "underline overline line-through blink", "-moz-anchor-decoration", "blink -moz-anchor-decoration" ],
invalid_values: [ "none none", "underline none", "none underline", "blink none", "none blink", "line-through blink line-through", "underline overline line-through blink none", "underline overline line-throuh blink blink",
@ -3113,7 +3121,7 @@ var gCSSProperties = {
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [ "underline", "overline", "line-through", "blink", "blink line-through underline", "underline overline line-through blink", "-moz-anchor-decoration", "blink -moz-anchor-decoration" ],
other_values: [ "underline", "overline", "line-through", "line-through underline", "underline overline line-through", "-moz-anchor-decoration", "-moz-anchor-decoration" ],
invalid_values: [ "none none", "underline none", "none underline", "line-through blink line-through", "underline overline line-through blink none", "underline overline line-throuh blink blink" ]
},
"-moz-text-decoration-style": {

View File

@ -35,100 +35,106 @@ var tests = [
// When only text-decoration was specified, text-decoration should look like
// a longhand property.
{ decoration: "none",
line: null, color: null, style: null,
blink: null, line: null, color: null, style: null,
expectedValue: "none", expectedCSSValue: "none" },
{ decoration: "underline",
line: null, color: null, style: null,
blink: null, line: null, color: null, style: null,
expectedValue: "underline", expectedCSSValue: "underline" },
{ decoration: "overline",
line: null, color: null, style: null,
blink: null, line: null, color: null, style: null,
expectedValue: "overline", expectedCSSValue: "overline" },
{ decoration: "line-through",
line: null, color: null, style: null,
blink: null, line: null, color: null, style: null,
expectedValue: "line-through", expectedCSSValue: "line-through" },
{ decoration: "blink",
line: null, color: null, style: null,
blink: null, line: null, color: null, style: null,
expectedValue: "blink", expectedCSSValue: "blink" },
{ decoration: "underline overline",
line: null, color: null, style: null,
blink: null, line: null, color: null, style: null,
expectedValue: "underline overline",
expectedCSSValue: "underline overline" },
{ decoration: "underline line-through",
line: null, color: null, style: null,
blink: null, line: null, color: null, style: null,
expectedValue: "underline line-through",
expectedCSSValue: "underline line-through" },
{ decoration: "blink underline",
line: null, color: null, style: null,
blink: null, line: null, color: null, style: null,
expectedValue: "underline blink",
expectedCSSValue: "underline blink" },
{ decoration: "underline blink",
line: null, color: null, style: null,
blink: null, line: null, color: null, style: null,
expectedValue: "underline blink",
expectedCSSValue: "underline blink" },
// When only text-decoration-line or text-blink was specified,
// text-decoration should look like a longhand property.
{ decoration: null,
line: "blink", color: null, style: null,
blink: "blink", line: null, color: null, style: null,
expectedValue: "blink", expectedCSSValue: "blink" },
{ decoration: null,
line: "underline", color: null, style: null,
blink: null, line: "underline", color: null, style: null,
expectedValue: "underline", expectedCSSValue: "underline" },
{ decoration: null,
line: "overline", color: null, style: null,
blink: null, line: "overline", color: null, style: null,
expectedValue: "overline", expectedCSSValue: "overline" },
{ decoration: null,
line: "line-through", color: null, style: null,
blink: null, line: "line-through", color: null, style: null,
expectedValue: "line-through", expectedCSSValue: "line-through" },
{ decoration: null,
line: "blink underline", color: null, style: null,
blink: "blink", line: "underline", color: null, style: null,
expectedValue: "underline blink", expectedCSSValue: "underline blink" },
{ decoration: null,
blink: "none", line: "underline", color: null, style: null,
expectedValue: "underline", expectedCSSValue: "underline" },
{ decoration: null,
blink: "blink", line: "none", color: null, style: null,
expectedValue: "blink", expectedCSSValue: "blink" },
// When text-decoration-color isn't its initial value,
// text-decoration should be a shorthand property.
{ decoration: "blink",
line: null, color: "rgb(0, 0, 0)", style: null,
blink: null, line: null, color: "rgb(0, 0, 0)", style: null,
expectedValue: "", expectedCSSValue: null },
{ decoration: "underline",
line: null, color: "black", style: null,
blink: null, line: null, color: "black", style: null,
expectedValue: "", expectedCSSValue: null },
{ decoration: "overline",
line: null, color: "#ff0000", style: null,
blink: null, line: null, color: "#ff0000", style: null,
expectedValue: "", expectedCSSValue: null },
{ decoration: "line-through",
line: null, color: "initial", style: null,
blink: null, line: null, color: "initial", style: null,
expectedValue: "line-through", expectedCSSValue: "line-through" },
{ decoration: "blink underline",
line: null, color: "currentColor", style: null,
blink: null, line: null, color: "currentColor", style: null,
expectedValue: "underline blink", expectedCSSValue: "underline blink" },
{ decoration: "underline line-through",
line: null, color: "-moz-use-text-color", style: null,
blink: null, line: null, color: "-moz-use-text-color", style: null,
expectedValue: "underline line-through",
expectedCSSValue: "underline line-through" },
// When text-decoration-style isn't its initial value,
// text-decoration should be a shorthand property.
{ decoration: "blink",
line: null, color: null, style: "-moz-none",
blink: null, line: null, color: null, style: "-moz-none",
expectedValue: "", expectedCSSValue: null },
{ decoration: "underline",
line: null, color: null, style: "dotted",
blink: null, line: null, color: null, style: "dotted",
expectedValue: "", expectedCSSValue: null },
{ decoration: "overline",
line: null, color: null, style: "dashed",
blink: null, line: null, color: null, style: "dashed",
expectedValue: "", expectedCSSValue: null },
{ decoration: "line-through",
line: null, color: null, style: "double",
blink: null, line: null, color: null, style: "double",
expectedValue: "", expectedCSSValue: null },
{ decoration: "blink underline",
line: null, color: null, style: "wavy",
blink: null, line: null, color: null, style: "wavy",
expectedValue: "", expectedCSSValue: null },
{ decoration: "underline blink overline line-through",
line: null, color: null, style: "solid",
blink: null, line: null, color: null, style: "solid",
expectedValue: "underline overline line-through blink",
expectedCSSValue: "underline overline line-through blink" },
{ decoration: "line-through overline underline",
line: null, color: null, style: "initial",
blink: null, line: null, color: null, style: "initial",
expectedValue: "underline overline line-through",
expectedCSSValue: "underline overline line-through" }
];
@ -139,6 +145,9 @@ function makeDeclaration(aTest)
if (aTest.decoration) {
str += "text-decoration: " + aTest.decoration + "; ";
}
if (aTest.blink) {
str += "-moz-text-blink: " + aTest.blink + "; ";
}
if (aTest.color) {
str += "-moz-text-decoration-color: " + aTest.color + "; ";
}
@ -161,6 +170,9 @@ for (var i = 0; i < tests.length; ++i) {
if (test.decoration) {
$('t').style.textDecoration = test.decoration;
}
if (test.blink) {
$('t').style.MozTextBlink = test.blink;
}
if (test.color) {
$('t').style.MozTextDecorationColor = test.color;
}

View File

@ -183,7 +183,6 @@ abstract public class GeckoApp
private static GeckoApp sAppContext;
protected MenuPanel mMenuPanel;
protected Menu mMenu;
private static GeckoThread sGeckoThread;
protected GeckoProfile mProfile;
public static int mOrientation;
protected boolean mIsRestoringActivity;
@ -1213,7 +1212,7 @@ abstract public class GeckoApp
return;
}
if (sGeckoThread != null) {
if (GeckoThread.isCreated()) {
// This happens when the GeckoApp activity is destroyed by Android
// without killing the entire application (see Bug 769269).
mIsRestoringActivity = true;
@ -1438,18 +1437,20 @@ abstract public class GeckoApp
Telemetry.HistogramAdd("FENNEC_STARTUP_GECKOAPP_ACTION", startupAction.ordinal());
if (!mIsRestoringActivity) {
sGeckoThread = new GeckoThread(intent, passedUri);
GeckoThread.setArgs(intent.getStringExtra("args"));
GeckoThread.setAction(intent.getAction());
GeckoThread.setUri(passedUri);
}
if (!ACTION_DEBUG.equals(action) &&
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) {
sGeckoThread.start();
GeckoThread.createAndStart();
} else if (ACTION_DEBUG.equals(action) &&
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.WaitForDebugger)) {
ThreadUtils.getUiHandler().postDelayed(new Runnable() {
@Override
public void run() {
GeckoThread.setLaunchState(GeckoThread.LaunchState.Launching);
sGeckoThread.start();
GeckoThread.createAndStart();
}
}, 1000 * 5 /* 5 seconds */);
}

View File

@ -38,16 +38,53 @@ public class GeckoThread extends Thread implements GeckoEventListener {
private static LaunchState sLaunchState = LaunchState.Launching;
private Intent mIntent;
private static GeckoThread sGeckoThread;
private final String mArgs;
private final String mAction;
private final String mUri;
GeckoThread(Intent intent, String uri) {
mIntent = intent;
public static boolean ensureInit() {
ThreadUtils.assertOnUiThread();
if (isCreated())
return false;
sGeckoThread = new GeckoThread(sArgs, sAction, sUri);
return true;
}
public static String sArgs;
public static String sAction;
public static String sUri;
public static void setArgs(String args) {
sArgs = args;
}
public static void setAction(String action) {
sAction = action;
}
public static void setUri(String uri) {
sUri = uri;
}
GeckoThread(String args, String action, String uri) {
mArgs = args;
mAction = action;
mUri = uri;
setName("Gecko");
GeckoAppShell.getEventDispatcher().registerEventListener("Gecko:Ready", this);
}
public static boolean isCreated() {
return sGeckoThread != null;
}
public static void createAndStart() {
if (ensureInit())
sGeckoThread.start();
}
private String initGeckoEnvironment() {
// At some point while loading the gecko libs our default locale gets set
// so just save it to locale here and reset it as default after the join
@ -123,9 +160,8 @@ public class GeckoThread extends Thread implements GeckoEventListener {
Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - runGecko");
String args = addCustomProfileArg(mIntent.getStringExtra("args"));
String type = getTypeFromAction(mIntent.getAction());
mIntent = null;
String args = addCustomProfileArg(mArgs);
String type = getTypeFromAction(mAction);
// and then fire us up
Log.i(LOGTAG, "RunGecko - args = " + args);

View File

@ -28,7 +28,6 @@ import android.os.Handler;
public class GeckoView extends LayerView
implements GeckoEventListener, ContextGetter {
static GeckoThread sGeckoThread;
public GeckoView(Context context, AttributeSet attrs) {
super(context, attrs);
@ -37,11 +36,9 @@ public class GeckoView extends LayerView
String url = a.getString(R.styleable.GeckoView_url);
a.recycle();
Intent intent;
if (url == null) {
intent = new Intent(Intent.ACTION_MAIN);
} else {
intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
if (url != null) {
GeckoThread.setUri(url);
GeckoThread.setAction(Intent.ACTION_VIEW);
GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(url));
}
GeckoAppShell.setContextGetter(this);
@ -53,12 +50,11 @@ public class GeckoView extends LayerView
BrowserDB.initialize(profile.getName());
GeckoAppShell.registerEventListener("Gecko:Ready", this);
sGeckoThread = new GeckoThread(intent, url);
ThreadUtils.setUiThread(Thread.currentThread(), new Handler());
initializeView(GeckoAppShell.getEventDispatcher());
if (GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) {
GeckoAppShell.setLayerView(this);
sGeckoThread.start();
GeckoThread.createAndStart();
}
}

View File

@ -90,7 +90,7 @@ class JavaAddonManager implements GeckoEventListener {
Log.d(LOGTAG, "Attempting to load classes.dex file from " + zipFile + " and instantiate " + implClass);
try {
File tmpDir = mApplicationContext.getDir("dex", 0);
DexClassLoader loader = new DexClassLoader(zipFile, tmpDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader());
DexClassLoader loader = new DexClassLoader(zipFile, tmpDir.getAbsolutePath(), null, mApplicationContext.getClassLoader());
Class<?> c = loader.loadClass(implClass);
try {
Constructor<?> constructor = c.getDeclaredConstructor(Map.class);

View File

@ -4320,10 +4320,14 @@ var BrowserEventHandler = {
onDoubleTap: function(aData) {
let data = JSON.parse(aData);
let element = ElementTouchHelper.anyElementFromPoint(data.x, data.y);
// We only want to do this if reflow-on-zoom is enabled.
// We only want to do this if reflow-on-zoom is enabled, we don't already
// have a reflow-on-zoom event pending, and the element upon which the user
// double-tapped isn't of a type we want to avoid reflow-on-zoom.
if (BrowserEventHandler.mReflozPref &&
!BrowserApp.selectedTab._mReflozPoint) {
!BrowserApp.selectedTab._mReflozPoint &&
!this._shouldSuppressReflowOnZoom(element)) {
let data = JSON.parse(aData);
let zoomPointX = data.x;
let zoomPointY = data.y;
@ -4333,8 +4337,6 @@ var BrowserEventHandler = {
BrowserApp.selectedTab.probablyNeedRefloz = true;
}
let zoom = BrowserApp.selectedTab._zoom;
let element = ElementTouchHelper.anyElementFromPoint(data.x, data.y);
if (!element) {
this._zoomOut();
return;
@ -4350,6 +4352,28 @@ var BrowserEventHandler = {
}
},
/**
* Determine if reflow-on-zoom functionality should be suppressed, given a
* particular element. Double-tapping on the following elements suppresses
* reflow-on-zoom:
*
* <video>, <object>, <embed>, <applet>, <canvas>, <img>, <media>, <pre>
*/
_shouldSuppressReflowOnZoom: function(aElement) {
if (aElement instanceof Ci.nsIDOMHTMLVideoElement ||
aElement instanceof Ci.nsIDOMHTMLObjectElement ||
aElement instanceof Ci.nsIDOMHTMLEmbedElement ||
aElement instanceof Ci.nsIDOMHTMLAppletElement ||
aElement instanceof Ci.nsIDOMHTMLCanvasElement ||
aElement instanceof Ci.nsIDOMHTMLImageElement ||
aElement instanceof Ci.nsIDOMHTMLMediaElement ||
aElement instanceof Ci.nsIDOMHTMLPreElement) {
return true;
}
return false;
},
/* Zoom to an element, optionally keeping a particular part of it
* in view if it is really tall.
*/

View File

@ -98,6 +98,7 @@ static NS_DEFINE_CID(kSocketProviderServiceCID, NS_SOCKETPROVIDERSERVICE_CID);
#define BROWSER_PREF_PREFIX "browser.cache."
#define DONOTTRACK_HEADER_ENABLED "privacy.donottrackheader.enabled"
#define DONOTTRACK_HEADER_VALUE "privacy.donottrackheader.value"
#define DONOTTRACK_VALUE_UNSET 2
#ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
#define TELEMETRY_ENABLED "toolkit.telemetry.enabledPreRelease"
#else
@ -235,6 +236,13 @@ nsHttpHandler::~nsHttpHandler()
mPipelineTestTimer = nullptr;
}
if (!mDoNotTrackEnabled) {
Telemetry::Accumulate(Telemetry::DNT_USAGE, DONOTTRACK_VALUE_UNSET);
}
else {
Telemetry::Accumulate(Telemetry::DNT_USAGE, mDoNotTrackValue);
}
gHttpHandler = nullptr;
}

View File

@ -176,7 +176,7 @@ public:
bool mBatchInProgress;
int32_t mRelatedNotificationsCount;
TimeStamp mLastNotificationTimeStamp;
mozilla::TimeStamp mLastNotificationTimeStamp;
nsCOMPtr<nsITimer> mEndBatchTimer;
void MaybeBeginBatch();

View File

@ -1573,6 +1573,11 @@
"n_buckets": 50,
"description": "Time spent waiting on the cache service lock (ms) on the main thread in NSASYNCDOOMEVENT_RUN"
},
"DNT_USAGE": {
"kind": "enumerated",
"n_values": 3,
"description": "I want to be tracked, I do NOT want to be tracked, DNT unset"
},
"DNS_LOOKUP_METHOD2": {
"kind": "enumerated",
"n_values": 16,

View File

@ -51,7 +51,6 @@ var BuiltinProvider = {
"devtools": "resource:///modules/devtools",
"devtools/server": "resource://gre/modules/devtools/server",
"devtools/toolkit/webconsole": "resource://gre/modules/devtools/toolkit/webconsole",
"devtools/styleinspector/css-logic": "resource://gre/modules/devtools/styleinspector/css-logic",
// Allow access to xpcshell test items from the loader.
"xpcshell-test": "resource://test"
@ -86,8 +85,6 @@ var SrcdirProvider = {
let toolkitURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools"));
let serverURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "server"));
let webconsoleURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "webconsole"));
let cssLogicURI = this.fileURI(OS.Path.join(toolkitURI, "styleinspector", "css-logic"));
let mainURI = this.fileURI(OS.Path.join(srcdir, "browser", "devtools", "main.js"));
this.loader = new loader.Loader({
modules: {
@ -98,7 +95,6 @@ var SrcdirProvider = {
"devtools/server": serverURI,
"devtools/toolkit/webconsole": webconsoleURI,
"devtools": devtoolsURI,
"devtools/styleinspector/css-logic": cssLogicURI,
"main": mainURI
},
globals: loaderGlobals

View File

@ -10,6 +10,5 @@ PARALLEL_DIRS += [
'gcli',
'sourcemap',
'webconsole',
'apps',
'styleinspector'
'apps'
]

View File

@ -1,15 +0,0 @@
# 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/.
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
libs::
$(INSTALL) $(IFLAGS1) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools/styleinspector

View File

@ -1,5 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.