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;
}
Пример #2
0
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;
}