Bug 1135731 - fix encoding inconsistency in NS_NewXBLProtoImpl; r=mrbkap
authorTom Tromey <tromey@mozilla.com>
Fri, 13 Mar 2015 12:05:57 -0700
changeset 233630 4777149382bca67ab577ff7ee6430dec6a3dd583
parent 233629 1c9a8a1e12b753558f6356cc03ce0a40dcd5c3aa
child 233631 51ab04cf3b55e2b96846edb3fb3ca0c2be5fbda8
push id28421
push userphilringnalda@gmail.com
push dateMon, 16 Mar 2015 02:16:05 +0000
treeherdermozilla-central@e19b8b7c8343 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1135731
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1135731 - fix encoding inconsistency in NS_NewXBLProtoImpl; r=mrbkap
dom/xbl/nsXBLBinding.cpp
dom/xbl/nsXBLBinding.h
dom/xbl/nsXBLProtoImpl.cpp
dom/xbl/nsXBLProtoImpl.h
dom/xbl/nsXBLProtoImplMember.h
dom/xbl/nsXBLProtoImplMethod.cpp
dom/xbl/nsXBLProtoImplMethod.h
dom/xbl/nsXBLProtoImplProperty.cpp
dom/xbl/nsXBLProtoImplProperty.h
dom/xbl/nsXBLPrototypeBinding.cpp
dom/xbl/nsXBLPrototypeBinding.h
js/src/jsapi.cpp
js/src/jsapi.h
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -953,17 +953,17 @@ GetOrCreateMapEntryForPrototype(JSContex
   }
   return entry;
 }
 
 // static
 nsresult
 nsXBLBinding::DoInitJSClass(JSContext *cx,
                             JS::Handle<JSObject*> obj,
-                            const nsAFlatCString& aClassName,
+                            const nsAFlatString& aClassName,
                             nsXBLPrototypeBinding* aProtoBinding,
                             JS::MutableHandle<JSObject*> aClassObject,
                             bool* aNew)
 {
   MOZ_ASSERT(obj);
 
   // Note that, now that NAC reflectors are created in the XBL scope, the
   // reflector is not necessarily same-compartment with the document. So we'll
@@ -998,17 +998,17 @@ nsXBLBinding::DoInitJSClass(JSContext *c
   js::AssertSameCompartment(holder, xblScope);
   JSAutoCompartment ac(cx, holder);
 
   // Look up the class on the property holder. The only properties on the
   // holder should be class objects. If we don't find the class object, we need
   // to create and define it.
   JS::Rooted<JSObject*> proto(cx);
   JS::Rooted<JSPropertyDescriptor> desc(cx);
-  if (!JS_GetOwnPropertyDescriptor(cx, holder, aClassName.get(), &desc)) {
+  if (!JS_GetOwnUCPropertyDescriptor(cx, holder, aClassName.get(), &desc)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   *aNew = !desc.object();
   if (desc.object()) {
     proto = &desc.value().toObject();
     MOZ_ASSERT(JS_GetClass(js::UncheckedUnwrap(proto)) == &gPrototypeJSClass);
   } else {
 
@@ -1030,19 +1030,19 @@ nsXBLBinding::DoInitJSClass(JSContext *c
     ::JS_SetPrivate(proto, docInfo);
     NS_ADDREF(docInfo);
     JS_SetReservedSlot(proto, 0, PRIVATE_TO_JSVAL(aProtoBinding));
 
     // Next, enter the compartment of the property holder, wrap the proto, and
     // stick it on.
     JSAutoCompartment ac3(cx, holder);
     if (!JS_WrapObject(cx, &proto) ||
-        !JS_DefineProperty(cx, holder, aClassName.get(), proto,
-                           JSPROP_READONLY | JSPROP_PERMANENT,
-                           JS_STUBGETTER, JS_STUBSETTER))
+        !JS_DefineUCProperty(cx, holder, aClassName.get(), -1, proto,
+                             JSPROP_READONLY | JSPROP_PERMANENT,
+                             JS_STUBGETTER, JS_STUBSETTER))
     {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   // Whew. We have the proto. Wrap it back into the compartment of |obj|,
   // splice it in, and return it.
   JSAutoCompartment ac4(cx, obj);
@@ -1151,18 +1151,18 @@ nsXBLBinding::LookupMemberInternal(JSCon
     }
     return mNextBinding->LookupMemberInternal(aCx, aName, aNameAsId,
                                               aDesc, aXBLScope);
   }
 
   // Find our class object. It's in a protected scope and permanent just in case,
   // so should be there no matter what.
   JS::Rooted<JS::Value> classObject(aCx);
-  if (!JS_GetProperty(aCx, aXBLScope, PrototypeBinding()->ClassName().get(),
-                      &classObject)) {
+  if (!JS_GetUCProperty(aCx, aXBLScope, PrototypeBinding()->ClassName().get(),
+                        -1, &classObject)) {
     return false;
   }
 
   // The bound element may have been adoped by a document and have a different
   // wrapper (and different xbl scope) than when the binding was applied, in
   // this case getting the class object will fail. Behave as if the class
   // object did not exist.
   if (classObject.isUndefined()) {
--- a/dom/xbl/nsXBLBinding.h
+++ b/dom/xbl/nsXBLBinding.h
@@ -126,17 +126,17 @@ public:
   void AttributeChanged(nsIAtom* aAttribute, int32_t aNameSpaceID,
                         bool aRemoveFlag, bool aNotify);
 
   void ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument);
 
   void WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData);
 
   static nsresult DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> obj,
-                                const nsAFlatCString& aClassName,
+                                const nsAFlatString& aClassName,
                                 nsXBLPrototypeBinding* aProtoBinding,
                                 JS::MutableHandle<JSObject*> aClassObject,
                                 bool* aNew);
 
   bool AllowScripts();
 
   mozilla::dom::XBLChildrenElement* FindInsertionPointFor(nsIContent* aChild);
 
--- a/dom/xbl/nsXBLProtoImpl.cpp
+++ b/dom/xbl/nsXBLProtoImpl.cpp
@@ -94,38 +94,38 @@ nsXBLProtoImpl::InstallImplementation(ns
   //
   // Note: If |targetIsNew| is false, we'll early-return above. However, that only
   // tells us if the content-side object is new, which may be the case even if
   // we've already set up the binding on the XBL side. For example, if we apply
   // a binding #foo to a <span> when we've already applied it to a <div>, we'll
   // end up with a different content prototype, but we'll already have a property
   // holder called |foo| in the XBL scope. Check for that to avoid wasteful and
   // weird property holder duplication.
-  const char* className = aPrototypeBinding->ClassName().get();
+  const char16_t* className = aPrototypeBinding->ClassName().get();
   JS::Rooted<JSObject*> propertyHolder(cx);
   JS::Rooted<JSPropertyDescriptor> existingHolder(cx);
   if (scopeObject != globalObject &&
-      !JS_GetOwnPropertyDescriptor(cx, scopeObject, className, &existingHolder)) {
+      !JS_GetOwnUCPropertyDescriptor(cx, scopeObject, className, &existingHolder)) {
     return NS_ERROR_FAILURE;
   }
   bool propertyHolderIsNew = !existingHolder.object() || !existingHolder.value().isObject();
 
   if (!propertyHolderIsNew) {
     propertyHolder = &existingHolder.value().toObject();
   } else if (scopeObject != globalObject) {
 
     // This is just a property holder, so it doesn't need any special JSClass.
     propertyHolder = JS_NewObjectWithGivenProto(cx, nullptr, JS::NullPtr());
     NS_ENSURE_TRUE(propertyHolder, NS_ERROR_OUT_OF_MEMORY);
 
     // Define it as a property on the scopeObject, using the same name used on
     // the content side.
-    bool ok = JS_DefineProperty(cx, scopeObject, className, propertyHolder,
-                                JSPROP_PERMANENT | JSPROP_READONLY,
-                                JS_STUBGETTER, JS_STUBSETTER);
+    bool ok = JS_DefineUCProperty(cx, scopeObject, className, -1, propertyHolder,
+                                  JSPROP_PERMANENT | JSPROP_READONLY,
+                                  JS_STUBGETTER, JS_STUBSETTER);
     NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
   } else {
     propertyHolder = targetClassObject;
   }
 
   // Walk our member list and install each one in turn on the XBL scope object.
   if (propertyHolderIsNew) {
     for (nsXBLProtoImplMember* curr = mMembers;
@@ -485,17 +485,17 @@ nsXBLProtoImpl::Write(nsIObjectOutputStr
 {
   nsresult rv;
 
   if (!mPrecompiledMemberHolder) {
     rv = CompilePrototypeMembers(aBinding);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  rv = aStream->WriteStringZ(mClassName.get());
+  rv = aStream->WriteUtf8Z(mClassName.get());
   NS_ENSURE_SUCCESS(rv, rv);
 
   for (nsXBLProtoImplField* curr = mFields; curr; curr = curr->GetNext()) {
     rv = curr->Write(aStream);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext()) {
     if (curr == mConstructor) {
@@ -514,18 +514,22 @@ nsXBLProtoImpl::Write(nsIObjectOutputStr
 }
 
 nsresult
 NS_NewXBLProtoImpl(nsXBLPrototypeBinding* aBinding, 
                    const char16_t* aClassName, 
                    nsXBLProtoImpl** aResult)
 {
   nsXBLProtoImpl* impl = new nsXBLProtoImpl();
-  if (aClassName)
-    impl->mClassName.AssignWithConversion(aClassName);
-  else
-    aBinding->BindingURI()->GetSpec(impl->mClassName);
+  if (aClassName) {
+    impl->mClassName = aClassName;
+  } else {
+    nsCString spec;
+    aBinding->BindingURI()->GetSpec(spec);
+    impl->mClassName = NS_ConvertUTF8toUTF16(spec);
+  }
+
   aBinding->SetImplementation(impl);
   *aResult = impl;
 
   return NS_OK;
 }
 
--- a/dom/xbl/nsXBLProtoImpl.h
+++ b/dom/xbl/nsXBLProtoImpl.h
@@ -96,17 +96,17 @@ protected:
     else
       mMembers = aMember;
     return aMember;
   }
 
   void DestroyMembers();
 
 public:
-  nsCString mClassName; // The name of the class.
+  nsString mClassName; // The name of the class.
 
 protected:
   JSObject* mPrecompiledMemberHolder; // The class object for the binding. We'll use this to pre-compile properties
                           // and methods for the binding.
 
   nsXBLProtoImplMember* mMembers; // The members of an implementation are chained in this singly-linked list.
 
   nsXBLProtoImplField* mFields; // Our fields
--- a/dom/xbl/nsXBLProtoImplMember.h
+++ b/dom/xbl/nsXBLProtoImplMember.h
@@ -75,17 +75,17 @@ public:
   nsXBLProtoImplMember* GetNext() { return mNext; }
   void SetNext(nsXBLProtoImplMember* aNext) { mNext = aNext; }
   bool ShouldExposeToUntrustedContent() { return mExposeToUntrustedContent; }
   void SetExposeToUntrustedContent(bool aExpose) { mExposeToUntrustedContent = aExpose; }
   const char16_t* GetName() { return mName; }
 
   virtual nsresult InstallMember(JSContext* aCx,
                                  JS::Handle<JSObject*> aTargetClassObject) = 0;
-  virtual nsresult CompileMember(mozilla::dom::AutoJSAPI& jsapi, const nsCString& aClassStr,
+  virtual nsresult CompileMember(mozilla::dom::AutoJSAPI& jsapi, const nsString& aClassStr,
                                  JS::Handle<JSObject*> aClassObject) = 0;
 
   virtual void Trace(const TraceCallbacks& aCallbacks, void *aClosure) = 0;
 
   virtual nsresult Write(nsIObjectOutputStream* aStream)
   {
     return NS_OK;
   }
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -127,17 +127,17 @@ nsXBLProtoImplMethod::InstallMember(JSCo
                                JSPROP_ENUMERATE)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
   return NS_OK;
 }
 
 nsresult
-nsXBLProtoImplMethod::CompileMember(AutoJSAPI& jsapi, const nsCString& aClassStr,
+nsXBLProtoImplMethod::CompileMember(AutoJSAPI& jsapi, const nsString& aClassStr,
                                     JS::Handle<JSObject*> aClassObject)
 {
   AssertInCompilationScope();
   NS_PRECONDITION(!IsCompiled(),
                   "Trying to compile an already-compiled method");
   NS_PRECONDITION(aClassObject,
                   "Must have class object to compile");
 
@@ -184,17 +184,17 @@ nsXBLProtoImplMethod::CompileMember(Auto
   nsDependentString body;
   char16_t *bodyText = uncompiledMethod->mBodyText.GetText();
   if (bodyText)
     body.Rebind(bodyText);
 
   // Now that we have a body and args, compile the function
   // and then define it.
   NS_ConvertUTF16toUTF8 cname(mName);
-  nsAutoCString functionUri(aClassStr);
+  NS_ConvertUTF16toUTF8 functionUri(aClassStr);
   int32_t hash = functionUri.RFindChar('#');
   if (hash != kNotFound) {
     functionUri.Truncate(hash);
   }
 
   JSContext *cx = jsapi.cx();
   JSAutoCompartment ac(cx, aClassObject);
   JS::CompileOptions options(cx);
--- a/dom/xbl/nsXBLProtoImplMethod.h
+++ b/dom/xbl/nsXBLProtoImplMethod.h
@@ -86,17 +86,17 @@ public:
 
   void AppendBodyText(const nsAString& aBody);
   void AddParameter(const nsAString& aName);
 
   void SetLineNumber(uint32_t aLineNumber);
   
   virtual nsresult InstallMember(JSContext* aCx,
                                  JS::Handle<JSObject*> aTargetClassObject) MOZ_OVERRIDE;
-  virtual nsresult CompileMember(mozilla::dom::AutoJSAPI& jsapi, const nsCString& aClassStr,
+  virtual nsresult CompileMember(mozilla::dom::AutoJSAPI& jsapi, const nsString& aClassStr,
                                  JS::Handle<JSObject*> aClassObject) MOZ_OVERRIDE;
 
   virtual void Trace(const TraceCallbacks& aCallbacks, void *aClosure) MOZ_OVERRIDE;
 
   nsresult Read(nsIObjectInputStream* aStream);
   virtual nsresult Write(nsIObjectOutputStream* aStream) MOZ_OVERRIDE;
 
   bool IsCompiled() const
--- a/dom/xbl/nsXBLProtoImplProperty.cpp
+++ b/dom/xbl/nsXBLProtoImplProperty.cpp
@@ -159,17 +159,17 @@ nsXBLProtoImplProperty::InstallMember(JS
                                JS_DATA_TO_FUNC_PTR(JSNative, getter.get()),
                                JS_DATA_TO_FUNC_PTR(JSNative, setter.get())))
       return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 nsresult
-nsXBLProtoImplProperty::CompileMember(AutoJSAPI& jsapi, const nsCString& aClassStr,
+nsXBLProtoImplProperty::CompileMember(AutoJSAPI& jsapi, const nsString& aClassStr,
                                       JS::Handle<JSObject*> aClassObject)
 {
   AssertInCompilationScope();
   NS_PRECONDITION(!mIsCompiled,
                   "Trying to compile an already-compiled property");
   NS_PRECONDITION(aClassObject,
                   "Must have class object to compile");
   MOZ_ASSERT(!mGetter.IsCompiled() && !mSetter.IsCompiled());
@@ -178,17 +178,17 @@ nsXBLProtoImplProperty::CompileMember(Au
   if (!mName)
     return NS_ERROR_FAILURE; // Without a valid name, we can't install the member.
 
   // We have a property.
   nsresult rv = NS_OK;
 
   nsAutoCString functionUri;
   if (mGetter.GetUncompiled() || mSetter.GetUncompiled()) {
-    functionUri = aClassStr;
+    functionUri = NS_ConvertUTF16toUTF8(aClassStr);
     int32_t hash = functionUri.RFindChar('#');
     if (hash != kNotFound) {
       functionUri.Truncate(hash);
     }
   }
 
   bool deletedGetter = false;
   nsXBLTextWithLineNumber *getterText = mGetter.GetUncompiled();
--- a/dom/xbl/nsXBLProtoImplProperty.h
+++ b/dom/xbl/nsXBLProtoImplProperty.h
@@ -30,17 +30,17 @@ public:
   void AppendGetterText(const nsAString& aGetter);
   void AppendSetterText(const nsAString& aSetter);
 
   void SetGetterLineNumber(uint32_t aLineNumber);
   void SetSetterLineNumber(uint32_t aLineNumber);
 
   virtual nsresult InstallMember(JSContext* aCx,
                                  JS::Handle<JSObject*> aTargetClassObject) MOZ_OVERRIDE;
-  virtual nsresult CompileMember(mozilla::dom::AutoJSAPI& jsapi, const nsCString& aClassStr,
+  virtual nsresult CompileMember(mozilla::dom::AutoJSAPI& jsapi, const nsString& aClassStr,
                                  JS::Handle<JSObject*> aClassObject) MOZ_OVERRIDE;
 
   virtual void Trace(const TraceCallbacks& aCallback, void *aClosure) MOZ_OVERRIDE;
 
   nsresult Read(nsIObjectInputStream* aStream,
                 XBLBindingSerializeDetails aType);
   virtual nsresult Write(nsIObjectOutputStream* aStream) MOZ_OVERRIDE;
 
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -447,17 +447,17 @@ nsXBLPrototypeBinding::GetImmediateChild
       return child;
     }
   }
 
   return nullptr;
 }
 
 nsresult
-nsXBLPrototypeBinding::InitClass(const nsCString& aClassName,
+nsXBLPrototypeBinding::InitClass(const nsString& aClassName,
                                  JSContext * aContext,
                                  JS::Handle<JSObject*> aScriptObject,
                                  JS::MutableHandle<JSObject*> aClassObject,
                                  bool* aNew)
 {
   return nsXBLBinding::DoInitJSClass(aContext, aScriptObject,
                                      aClassName, this, aClassObject, aNew);
 }
@@ -1126,17 +1126,17 @@ nsXBLPrototypeBinding::Write(nsIObjectOu
   // Write out the implementation details.
   if (mImplementation) {
     rv = mImplementation->Write(aStream, this);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
     // Write out an empty classname. This indicates that the binding does not
     // define an implementation.
-    rv = aStream->WriteWStringZ(EmptyString().get());
+    rv = aStream->WriteUtf8Z(EmptyString().get());
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Write out the handlers.
   nsXBLPrototypeHandler* handler = mPrototypeHandler;
   while (handler) {
     rv = handler->Write(aStream);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/xbl/nsXBLPrototypeBinding.h
+++ b/dom/xbl/nsXBLPrototypeBinding.h
@@ -84,21 +84,21 @@ public:
   // Undefine all our fields from object |obj| (which should be a
   // JSObject for a bound element).
   void UndefineFields(JSContext* cx, JS::Handle<JSObject*> obj) const {
     if (mImplementation) {
       mImplementation->UndefineFields(cx, obj);
     }
   }
 
-  const nsCString& ClassName() const {
-    return mImplementation ? mImplementation->mClassName : EmptyCString();
+  const nsString& ClassName() const {
+    return mImplementation ? mImplementation->mClassName : EmptyString();
   }
 
-  nsresult InitClass(const nsCString& aClassName, JSContext * aContext,
+  nsresult InitClass(const nsString& aClassName, JSContext* aContext,
                      JS::Handle<JSObject*> aScriptObject,
                      JS::MutableHandle<JSObject*> aClassObject,
                      bool* aNew);
 
   nsresult ConstructInterfaceTable(const nsAString& aImpls);
 
   void SetImplementation(nsXBLProtoImpl* aImpl) { mImplementation = aImpl; }
   nsXBLProtoImpl* GetImplementation() { return mImplementation; }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2749,16 +2749,27 @@ JS_GetOwnPropertyDescriptor(JSContext *c
     JSAtom *atom = Atomize(cx, name, strlen(name));
     if (!atom)
         return false;
     RootedId id(cx, AtomToId(atom));
     return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc);
 }
 
 JS_PUBLIC_API(bool)
+JS_GetOwnUCPropertyDescriptor(JSContext *cx, HandleObject obj, const char16_t *name,
+                              MutableHandle<JSPropertyDescriptor> desc)
+{
+    JSAtom *atom = AtomizeChars(cx, name, js_strlen(name));
+    if (!atom)
+        return false;
+    RootedId id(cx, AtomToId(atom));
+    return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc);
+}
+
+JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id,
                              MutableHandle<JSPropertyDescriptor> desc)
 {
     return GetPropertyDescriptor(cx, obj, id, desc);
 }
 
 JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptor(JSContext *cx, HandleObject obj, const char *name,
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2841,16 +2841,20 @@ JS_HasPropertyById(JSContext *cx, JS::Ha
 extern JS_PUBLIC_API(bool)
 JS_GetOwnPropertyDescriptorById(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                                 JS::MutableHandle<JSPropertyDescriptor> desc);
 
 extern JS_PUBLIC_API(bool)
 JS_GetOwnPropertyDescriptor(JSContext *cx, JS::HandleObject obj, const char *name,
                             JS::MutableHandle<JSPropertyDescriptor> desc);
 
+extern JS_PUBLIC_API(bool)
+JS_GetOwnUCPropertyDescriptor(JSContext *cx, JS::HandleObject obj, const char16_t *name,
+                              JS::MutableHandle<JSPropertyDescriptor> desc);
+
 /*
  * Like JS_GetOwnPropertyDescriptorById but will return a property on
  * an object on the prototype chain (returned in desc->obj). If desc->obj is null,
  * then this property was not found on the prototype chain.
  */
 extern JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptorById(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                              JS::MutableHandle<JSPropertyDescriptor> desc);