LCOV - code coverage report
Current view: top level - dom/xbl - nsXBLProtoImplProperty.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 52 194 26.8 %
Date: 2017-07-14 16:53:18 Functions: 4 14 28.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsIAtom.h"
       8             : #include "nsString.h"
       9             : #include "jsapi.h"
      10             : #include "nsIContent.h"
      11             : #include "nsXBLProtoImplProperty.h"
      12             : #include "nsUnicharUtils.h"
      13             : #include "nsReadableUtils.h"
      14             : #include "nsJSUtils.h"
      15             : #include "nsXBLPrototypeBinding.h"
      16             : #include "nsXBLSerialize.h"
      17             : #include "xpcpublic.h"
      18             : 
      19             : using namespace mozilla;
      20             : using namespace mozilla::dom;
      21             : 
      22           0 : nsXBLProtoImplProperty::nsXBLProtoImplProperty(const char16_t* aName,
      23             :                                                const char16_t* aGetter,
      24             :                                                const char16_t* aSetter,
      25             :                                                const char16_t* aReadOnly,
      26           0 :                                                uint32_t aLineNumber) :
      27             :   nsXBLProtoImplMember(aName),
      28             :   mJSAttributes(JSPROP_ENUMERATE)
      29             : #ifdef DEBUG
      30           0 :   , mIsCompiled(false)
      31             : #endif
      32             : {
      33           0 :   MOZ_COUNT_CTOR(nsXBLProtoImplProperty);
      34             : 
      35           0 :   if (aReadOnly) {
      36           0 :     nsAutoString readOnly; readOnly.Assign(*aReadOnly);
      37           0 :     if (readOnly.LowerCaseEqualsLiteral("true"))
      38           0 :       mJSAttributes |= JSPROP_READONLY;
      39             :   }
      40             : 
      41           0 :   if (aGetter) {
      42           0 :     AppendGetterText(nsDependentString(aGetter));
      43           0 :     SetGetterLineNumber(aLineNumber);
      44             :   }
      45           0 :   if (aSetter) {
      46           0 :     AppendSetterText(nsDependentString(aSetter));
      47           0 :     SetSetterLineNumber(aLineNumber);
      48             :   }
      49           0 : }
      50             : 
      51         355 : nsXBLProtoImplProperty::nsXBLProtoImplProperty(const char16_t* aName,
      52         355 :                                                const bool aIsReadOnly)
      53             :   : nsXBLProtoImplMember(aName),
      54             :     mJSAttributes(JSPROP_ENUMERATE)
      55             : #ifdef DEBUG
      56         355 :   , mIsCompiled(false)
      57             : #endif
      58             : {
      59         355 :   MOZ_COUNT_CTOR(nsXBLProtoImplProperty);
      60             : 
      61         355 :   if (aIsReadOnly)
      62           0 :     mJSAttributes |= JSPROP_READONLY;
      63         355 : }
      64             : 
      65           0 : nsXBLProtoImplProperty::~nsXBLProtoImplProperty()
      66             : {
      67           0 :   MOZ_COUNT_DTOR(nsXBLProtoImplProperty);
      68             : 
      69           0 :   if (!mGetter.IsCompiled()) {
      70           0 :     delete mGetter.GetUncompiled();
      71             :   }
      72             : 
      73           0 :   if (!mSetter.IsCompiled()) {
      74           0 :     delete mSetter.GetUncompiled();
      75             :   }
      76           0 : }
      77             : 
      78           0 : void nsXBLProtoImplProperty::EnsureUncompiledText(PropertyOp& aPropertyOp)
      79             : {
      80           0 :   if (!aPropertyOp.GetUncompiled()) {
      81           0 :     nsXBLTextWithLineNumber* text = new nsXBLTextWithLineNumber();
      82           0 :     aPropertyOp.SetUncompiled(text);
      83             :   }
      84           0 : }
      85             : 
      86             : void
      87           0 : nsXBLProtoImplProperty::AppendGetterText(const nsAString& aText)
      88             : {
      89           0 :   NS_PRECONDITION(!mIsCompiled,
      90             :                   "Must not be compiled when accessing getter text");
      91           0 :   EnsureUncompiledText(mGetter);
      92           0 :   mGetter.GetUncompiled()->AppendText(aText);
      93           0 : }
      94             : 
      95             : void
      96           0 : nsXBLProtoImplProperty::AppendSetterText(const nsAString& aText)
      97             : {
      98           0 :   NS_PRECONDITION(!mIsCompiled,
      99             :                   "Must not be compiled when accessing setter text");
     100           0 :   EnsureUncompiledText(mSetter);
     101           0 :   mSetter.GetUncompiled()->AppendText(aText);
     102           0 : }
     103             : 
     104             : void
     105           0 : nsXBLProtoImplProperty::SetGetterLineNumber(uint32_t aLineNumber)
     106             : {
     107           0 :   NS_PRECONDITION(!mIsCompiled,
     108             :                   "Must not be compiled when accessing getter text");
     109           0 :   EnsureUncompiledText(mGetter);
     110           0 :   mGetter.GetUncompiled()->SetLineNumber(aLineNumber);
     111           0 : }
     112             : 
     113             : void
     114           0 : nsXBLProtoImplProperty::SetSetterLineNumber(uint32_t aLineNumber)
     115             : {
     116           0 :   NS_PRECONDITION(!mIsCompiled,
     117             :                   "Must not be compiled when accessing setter text");
     118           0 :   EnsureUncompiledText(mSetter);
     119           0 :   mSetter.GetUncompiled()->SetLineNumber(aLineNumber);
     120           0 : }
     121             : 
     122             : const char* gPropertyArgs[] = { "val" };
     123             : 
     124             : nsresult
     125         303 : nsXBLProtoImplProperty::InstallMember(JSContext *aCx,
     126             :                                       JS::Handle<JSObject*> aTargetClassObject)
     127             : {
     128         303 :   NS_PRECONDITION(mIsCompiled,
     129             :                   "Should not be installing an uncompiled property");
     130         303 :   MOZ_ASSERT(mGetter.IsCompiled() && mSetter.IsCompiled());
     131         303 :   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
     132             : 
     133             : #ifdef DEBUG
     134             :   {
     135         606 :     JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
     136         303 :     MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
     137             :                xpc::IsInAddonScope(globalObject) ||
     138             :                globalObject == xpc::GetXBLScope(aCx, globalObject));
     139         303 :     MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == globalObject);
     140             :   }
     141             : #endif
     142             : 
     143         606 :   JS::Rooted<JSObject*> getter(aCx, mGetter.GetJSFunction());
     144         606 :   JS::Rooted<JSObject*> setter(aCx, mSetter.GetJSFunction());
     145         303 :   if (getter || setter) {
     146         303 :     if (getter) {
     147         300 :       if (!(getter = JS::CloneFunctionObject(aCx, getter)))
     148           0 :         return NS_ERROR_OUT_OF_MEMORY;
     149             :     }
     150             : 
     151         303 :     if (setter) {
     152         128 :       if (!(setter = JS::CloneFunctionObject(aCx, setter)))
     153           0 :         return NS_ERROR_OUT_OF_MEMORY;
     154             :     }
     155             : 
     156         606 :     nsDependentString name(mName);
     157        1212 :     if (!::JS_DefineUCProperty(aCx, aTargetClassObject,
     158         303 :                                static_cast<const char16_t*>(mName),
     159         303 :                                name.Length(), JS::UndefinedHandleValue, mJSAttributes,
     160         303 :                                JS_DATA_TO_FUNC_PTR(JSNative, getter.get()),
     161         303 :                                JS_DATA_TO_FUNC_PTR(JSNative, setter.get())))
     162           0 :       return NS_ERROR_OUT_OF_MEMORY;
     163             :   }
     164         303 :   return NS_OK;
     165             : }
     166             : 
     167             : nsresult
     168           0 : nsXBLProtoImplProperty::CompileMember(AutoJSAPI& jsapi, const nsString& aClassStr,
     169             :                                       JS::Handle<JSObject*> aClassObject)
     170             : {
     171           0 :   AssertInCompilationScope();
     172           0 :   NS_PRECONDITION(!mIsCompiled,
     173             :                   "Trying to compile an already-compiled property");
     174           0 :   NS_PRECONDITION(aClassObject,
     175             :                   "Must have class object to compile");
     176           0 :   MOZ_ASSERT(!mGetter.IsCompiled() && !mSetter.IsCompiled());
     177           0 :   JSContext *cx = jsapi.cx();
     178             : 
     179           0 :   if (!mName)
     180           0 :     return NS_ERROR_FAILURE; // Without a valid name, we can't install the member.
     181             : 
     182             :   // We have a property.
     183           0 :   nsresult rv = NS_OK;
     184             : 
     185           0 :   nsAutoCString functionUri;
     186           0 :   if (mGetter.GetUncompiled() || mSetter.GetUncompiled()) {
     187           0 :     functionUri = NS_ConvertUTF16toUTF8(aClassStr);
     188           0 :     int32_t hash = functionUri.RFindChar('#');
     189           0 :     if (hash != kNotFound) {
     190           0 :       functionUri.Truncate(hash);
     191             :     }
     192             :   }
     193             : 
     194           0 :   bool deletedGetter = false;
     195           0 :   nsXBLTextWithLineNumber *getterText = mGetter.GetUncompiled();
     196           0 :   if (getterText && getterText->GetText()) {
     197           0 :     nsDependentString getter(getterText->GetText());
     198           0 :     if (!getter.IsEmpty()) {
     199           0 :       JSAutoCompartment ac(cx, aClassObject);
     200           0 :       JS::CompileOptions options(cx);
     201           0 :       options.setFileAndLine(functionUri.get(), getterText->GetLineNumber())
     202           0 :              .setVersion(JSVERSION_LATEST);
     203           0 :       nsCString name = NS_LITERAL_CSTRING("get_") + NS_ConvertUTF16toUTF8(mName);
     204           0 :       JS::Rooted<JSObject*> getterObject(cx);
     205           0 :       JS::AutoObjectVector emptyVector(cx);
     206           0 :       rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, name, 0,
     207           0 :                                       nullptr, getter, getterObject.address());
     208             : 
     209           0 :       delete getterText;
     210           0 :       deletedGetter = true;
     211             : 
     212           0 :       mGetter.SetJSFunction(getterObject);
     213             : 
     214           0 :       if (mGetter.GetJSFunction() && NS_SUCCEEDED(rv)) {
     215           0 :         mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
     216             :       }
     217           0 :       if (NS_FAILED(rv)) {
     218           0 :         mGetter.SetJSFunction(nullptr);
     219           0 :         mJSAttributes &= ~JSPROP_GETTER;
     220             :         /*chaining to return failure*/
     221             :       }
     222             :     }
     223             :   } // if getter is not empty
     224             : 
     225           0 :   if (!deletedGetter) {  // Empty getter
     226           0 :     delete getterText;
     227           0 :     mGetter.SetJSFunction(nullptr);
     228             :   }
     229             : 
     230           0 :   if (NS_FAILED(rv)) {
     231             :     // We failed to compile our getter.  So either we've set it to null, or
     232             :     // it's still set to the text object.  In either case, it's safe to return
     233             :     // the error here, since then we'll be cleaned up as uncompiled and that
     234             :     // will be ok.  Going on and compiling the setter and _then_ returning an
     235             :     // error, on the other hand, will try to clean up a compiled setter as
     236             :     // uncompiled and crash.
     237           0 :     return rv;
     238             :   }
     239             : 
     240           0 :   bool deletedSetter = false;
     241           0 :   nsXBLTextWithLineNumber *setterText = mSetter.GetUncompiled();
     242           0 :   if (setterText && setterText->GetText()) {
     243           0 :     nsDependentString setter(setterText->GetText());
     244           0 :     if (!setter.IsEmpty()) {
     245           0 :       JSAutoCompartment ac(cx, aClassObject);
     246           0 :       JS::CompileOptions options(cx);
     247           0 :       options.setFileAndLine(functionUri.get(), setterText->GetLineNumber())
     248           0 :              .setVersion(JSVERSION_LATEST);
     249           0 :       nsCString name = NS_LITERAL_CSTRING("set_") + NS_ConvertUTF16toUTF8(mName);
     250           0 :       JS::Rooted<JSObject*> setterObject(cx);
     251           0 :       JS::AutoObjectVector emptyVector(cx);
     252           0 :       rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, name, 1,
     253             :                                       gPropertyArgs, setter,
     254           0 :                                       setterObject.address());
     255             : 
     256           0 :       delete setterText;
     257           0 :       deletedSetter = true;
     258           0 :       mSetter.SetJSFunction(setterObject);
     259             : 
     260           0 :       if (mSetter.GetJSFunction() && NS_SUCCEEDED(rv)) {
     261           0 :         mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
     262             :       }
     263           0 :       if (NS_FAILED(rv)) {
     264           0 :         mSetter.SetJSFunction(nullptr);
     265           0 :         mJSAttributes &= ~JSPROP_SETTER;
     266             :         /*chaining to return failure*/
     267             :       }
     268             :     }
     269             :   } // if setter wasn't empty....
     270             : 
     271           0 :   if (!deletedSetter) {  // Empty setter
     272           0 :     delete setterText;
     273           0 :     mSetter.SetJSFunction(nullptr);
     274             :   }
     275             : 
     276             : #ifdef DEBUG
     277           0 :   mIsCompiled = NS_SUCCEEDED(rv);
     278             : #endif
     279             : 
     280           0 :   return rv;
     281             : }
     282             : 
     283             : void
     284         355 : nsXBLProtoImplProperty::Trace(const TraceCallbacks& aCallbacks, void *aClosure)
     285             : {
     286         355 :   if (mJSAttributes & JSPROP_GETTER) {
     287         352 :     aCallbacks.Trace(&mGetter.AsHeapObject(), "mGetter", aClosure);
     288             :   }
     289             : 
     290         355 :   if (mJSAttributes & JSPROP_SETTER) {
     291         160 :     aCallbacks.Trace(&mSetter.AsHeapObject(), "mSetter", aClosure);
     292             :   }
     293         355 : }
     294             : 
     295             : nsresult
     296         355 : nsXBLProtoImplProperty::Read(nsIObjectInputStream* aStream,
     297             :                              XBLBindingSerializeDetails aType)
     298             : {
     299         355 :   AssertInCompilationScope();
     300         355 :   MOZ_ASSERT(!mIsCompiled);
     301         355 :   MOZ_ASSERT(!mGetter.GetUncompiled() && !mSetter.GetUncompiled());
     302             : 
     303         710 :   AutoJSContext cx;
     304         710 :   JS::Rooted<JSObject*> getterObject(cx);
     305         355 :   if (aType == XBLBinding_Serialize_GetterProperty ||
     306             :       aType == XBLBinding_Serialize_GetterSetterProperty) {
     307         352 :     nsresult rv = XBL_DeserializeFunction(aStream, &getterObject);
     308         352 :     NS_ENSURE_SUCCESS(rv, rv);
     309             : 
     310         352 :     mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
     311             :   }
     312         355 :   mGetter.SetJSFunction(getterObject);
     313             : 
     314         710 :   JS::Rooted<JSObject*> setterObject(cx);
     315         355 :   if (aType == XBLBinding_Serialize_SetterProperty ||
     316             :       aType == XBLBinding_Serialize_GetterSetterProperty) {
     317         160 :     nsresult rv = XBL_DeserializeFunction(aStream, &setterObject);
     318         160 :     NS_ENSURE_SUCCESS(rv, rv);
     319             : 
     320         160 :     mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
     321             :   }
     322         355 :   mSetter.SetJSFunction(setterObject);
     323             : 
     324             : #ifdef DEBUG
     325         355 :   mIsCompiled = true;
     326             : #endif
     327             : 
     328         355 :   return NS_OK;
     329             : }
     330             : 
     331             : nsresult
     332           0 : nsXBLProtoImplProperty::Write(nsIObjectOutputStream* aStream)
     333             : {
     334           0 :   AssertInCompilationScope();
     335             :   XBLBindingSerializeDetails type;
     336             : 
     337           0 :   if (mJSAttributes & JSPROP_GETTER) {
     338           0 :     type = mJSAttributes & JSPROP_SETTER ?
     339             :            XBLBinding_Serialize_GetterSetterProperty :
     340           0 :            XBLBinding_Serialize_GetterProperty;
     341             :   }
     342             :   else {
     343           0 :     type = XBLBinding_Serialize_SetterProperty;
     344             :   }
     345             : 
     346           0 :   if (mJSAttributes & JSPROP_READONLY) {
     347           0 :     type |= XBLBinding_Serialize_ReadOnly;
     348             :   }
     349             : 
     350           0 :   nsresult rv = aStream->Write8(type);
     351           0 :   NS_ENSURE_SUCCESS(rv, rv);
     352           0 :   rv = aStream->WriteWStringZ(mName);
     353           0 :   NS_ENSURE_SUCCESS(rv, rv);
     354             : 
     355           0 :   MOZ_ASSERT_IF(mJSAttributes & (JSPROP_GETTER | JSPROP_SETTER), mIsCompiled);
     356             : 
     357           0 :   if (mJSAttributes & JSPROP_GETTER) {
     358           0 :     JS::Rooted<JSObject*> function(RootingCx(), mGetter.GetJSFunction());
     359           0 :     rv = XBL_SerializeFunction(aStream, function);
     360           0 :     NS_ENSURE_SUCCESS(rv, rv);
     361             :   }
     362             : 
     363           0 :   if (mJSAttributes & JSPROP_SETTER) {
     364           0 :     JS::Rooted<JSObject*> function(RootingCx(), mSetter.GetJSFunction());
     365           0 :     rv = XBL_SerializeFunction(aStream, function);
     366           0 :     NS_ENSURE_SUCCESS(rv, rv);
     367             :   }
     368             : 
     369           0 :   return NS_OK;
     370             : }

Generated by: LCOV version 1.13