nsresult nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr, JSObject* aClassObject) { NS_PRECONDITION(!mIsCompiled, "Trying to compile an already-compiled property"); NS_PRECONDITION(aClassObject, "Must have class object to compile"); 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 (mGetterText || mSetterText) { functionUri = aClassStr; int32_t hash = functionUri.RFindChar('#'); if (hash != kNotFound) { functionUri.Truncate(hash); } } bool deletedGetter = false; if (mGetterText && mGetterText->GetText()) { nsDependentString getter(mGetterText->GetText()); if (!getter.IsEmpty()) { // Compile into a temp object so we don't wipe out mGetterText JSObject* getterObject = nullptr; JSContext* cx = aContext->GetNativeContext(); JSAutoRequest ar(cx); JSAutoCompartment ac(cx, aClassObject); JS::CompileOptions options(cx); options.setFileAndLine(functionUri.get(), mGetterText->GetLineNumber()) .setVersion(JSVERSION_LATEST) .setUserBit(true); // Flag us as XBL nsCString name = NS_LITERAL_CSTRING("get_") + NS_ConvertUTF16toUTF8(mName); js::RootedObject rootedNull(cx, nullptr); // See bug 781070. rv = nsJSUtils::CompileFunction(cx, rootedNull, options, name, 0, nullptr, getter, &getterObject); // Make sure we free mGetterText here before setting mJSGetterObject, since // that'll overwrite mGetterText delete mGetterText; deletedGetter = true; mJSGetterObject = getterObject; if (mJSGetterObject && NS_SUCCEEDED(rv)) { mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED; } if (NS_FAILED(rv)) { mJSGetterObject = nullptr; mJSAttributes &= ~JSPROP_GETTER; /*chaining to return failure*/ } } } // if getter is not empty if (!deletedGetter) { // Empty getter delete mGetterText; mJSGetterObject = nullptr; } if (NS_FAILED(rv)) { // We failed to compile our getter. So either we've set it to null, or // it's still set to the text object. In either case, it's safe to return // the error here, since then we'll be cleaned up as uncompiled and that // will be ok. Going on and compiling the setter and _then_ returning an // error, on the other hand, will try to clean up a compiled setter as // uncompiled and crash. return rv; } bool deletedSetter = false; if (mSetterText && mSetterText->GetText()) { nsDependentString setter(mSetterText->GetText()); if (!setter.IsEmpty()) { // Compile into a temp object so we don't wipe out mSetterText JSObject* setterObject = nullptr; JSContext* cx = aContext->GetNativeContext(); JSAutoRequest ar(cx); JSAutoCompartment ac(cx, aClassObject); JS::CompileOptions options(cx); options.setFileAndLine(functionUri.get(), mSetterText->GetLineNumber()) .setVersion(JSVERSION_LATEST) .setUserBit(true); // Flag us as XBL nsCString name = NS_LITERAL_CSTRING("set_") + NS_ConvertUTF16toUTF8(mName); js::RootedObject rootedNull(cx, nullptr); // See bug 781070. rv = nsJSUtils::CompileFunction(cx, rootedNull, options, name, 1, gPropertyArgs, setter, &setterObject); // Make sure we free mSetterText here before setting mJSGetterObject, since // that'll overwrite mSetterText delete mSetterText; deletedSetter = true; mJSSetterObject = setterObject; if (mJSSetterObject && NS_SUCCEEDED(rv)) { mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED; } if (NS_FAILED(rv)) { mJSSetterObject = nullptr; mJSAttributes &= ~JSPROP_SETTER; /*chaining to return failure*/ } } } // if setter wasn't empty.... if (!deletedSetter) { // Empty setter delete mSetterText; mJSSetterObject = nullptr; } #ifdef DEBUG mIsCompiled = NS_SUCCEEDED(rv); #endif return rv; }
nsresult nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr, JSObject* aClassObject) { NS_PRECONDITION(!IsCompiled(), "Trying to compile an already-compiled method"); NS_PRECONDITION(aClassObject, "Must have class object to compile"); nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod(); // No parameters or body was supplied, so don't install method. if (!uncompiledMethod) { // Early return after which we consider ourselves compiled. mJSMethodObject = nullptr; return NS_OK; } // Don't install method if no name was supplied. if (!mName) { delete uncompiledMethod; // Early return after which we consider ourselves compiled. mJSMethodObject = nullptr; return NS_OK; } // We have a method. // Allocate an array for our arguments. int32_t paramCount = uncompiledMethod->GetParameterCount(); char** args = nullptr; if (paramCount > 0) { args = new char*[paramCount]; if (!args) return NS_ERROR_OUT_OF_MEMORY; // Add our parameters to our args array. int32_t argPos = 0; for (nsXBLParameter* curr = uncompiledMethod->mParameters; curr; curr = curr->mNext) { args[argPos] = curr->mName; argPos++; } } // Get the body nsDependentString body; PRUnichar *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); int32_t hash = functionUri.RFindChar('#'); if (hash != kNotFound) { functionUri.Truncate(hash); } JSObject* methodObject = nullptr; JSContext* cx = aContext->GetNativeContext(); JSAutoRequest ar(cx); JSAutoCompartment ac(cx, aClassObject); JS::CompileOptions options(cx); options.setFileAndLine(functionUri.get(), uncompiledMethod->mBodyText.GetLineNumber()) .setVersion(JSVERSION_LATEST) .setUserBit(true); // Flag us as XBL js::RootedObject rootedNull(cx, nullptr); // See bug 781070. nsresult rv = nsJSUtils::CompileFunction(cx, rootedNull, options, cname, paramCount, const_cast<const char**>(args), body, &methodObject); // Destroy our uncompiled method and delete our arg list. delete uncompiledMethod; delete [] args; if (NS_FAILED(rv)) { SetUncompiledMethod(nullptr); return rv; } mJSMethodObject = methodObject; return NS_OK; }