// static
JSObject*
DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj)
{
    MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
    JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
    if (v.isUndefined()) {
        return nullptr;
    }

    if (v.isObject()) {
        js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, UndefinedValue());
        xpc::GetObjectScope(obj)->RemoveDOMExpandoObject(obj);
    } else {
        js::ExpandoAndGeneration* expandoAndGeneration =
            static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
        v = expandoAndGeneration->expando;
        if (v.isUndefined()) {
            return nullptr;
        }
        expandoAndGeneration->expando = UndefinedValue();
    }


    return &v.toObject();
}
Esempio n. 2
0
void HostReleaseTopLevelScript(const JS::Value& aPrivate) {
  // Decrement the reference count of a LoadedScript object that was pointed to
  // by a JSScript. The reference count was originally incremented by
  // HostAddRefTopLevelScript() above.

  auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
  CheckModuleScriptPrivate(script, aPrivate);
  script->Release();
}
/**
 * Extract the FinalizationEvent from an instance of FinalizationWitness
 * and clear the slot containing the FinalizationEvent.
 */
already_AddRefed<FinalizationEvent>
ExtractFinalizationEvent(JSObject *objSelf)
{
  JS::Value slotEvent = JS_GetReservedSlot(objSelf, WITNESS_SLOT_EVENT);
  if (slotEvent.isUndefined()) {
    // Forget() has been called
    return nullptr;
  }

  JS_SetReservedSlot(objSelf, WITNESS_SLOT_EVENT, JS::UndefinedValue());

  return dont_AddRef(static_cast<FinalizationEvent*>(slotEvent.toPrivate()));
}
Esempio n. 4
0
void ShadowingDOMProxyHandler::trace(JSTracer* trc, JSObject* proxy) const {
  DOMProxyHandler::trace(trc, proxy);

  MOZ_ASSERT(IsDOMProxy(proxy), "expected a DOM proxy object");
  JS::Value v = js::GetProxyPrivate(proxy);
  MOZ_ASSERT(!v.isObject(), "Should not have expando object directly!");

  // The proxy's private slot is set when we allocate the proxy,
  // so it cannot be |undefined|.
  MOZ_ASSERT(!v.isUndefined());

  js::ExpandoAndGeneration* expandoAndGeneration =
      static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
  JS::TraceEdge(trc, &expandoAndGeneration->expando,
                "Shadowing DOM proxy expando");
}
// static
JSObject*
DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj)
{
    NS_ASSERTION(IsDOMProxy(obj), "expected a DOM proxy object");
    JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
    if (v.isObject()) {
        return &v.toObject();
    }

    js::ExpandoAndGeneration* expandoAndGeneration;
    if (!v.isUndefined()) {
        expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
        if (expandoAndGeneration->expando.isObject()) {
            return &expandoAndGeneration->expando.toObject();
        }
    } else {
        expandoAndGeneration = nullptr;
    }

    JS::Rooted<JSObject*> expando(cx,
                                  JS_NewObjectWithGivenProto(cx, nullptr, nullptr, js::GetObjectParent(obj)));
    if (!expando) {
        return nullptr;
    }

    nsISupports* native = UnwrapDOMObject<nsISupports>(obj);
    nsWrapperCache* cache;
    CallQueryInterface(native, &cache);
    if (expandoAndGeneration) {
        cache->PreserveWrapper(native);
        expandoAndGeneration->expando.setObject(*expando);

        return expando;
    }

    XPCWrappedNativeScope* scope = xpc::GetObjectScope(obj);
    if (!scope->RegisterDOMExpandoObject(obj)) {
        return nullptr;
    }

    cache->SetPreservingWrapper(true);
    js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando));

    return expando;
}
//static
JSObject *
DOMProxyHandler::GetExpandoObject(JSObject *obj)
{
  MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
  JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
  if (v.isObject()) {
    return &v.toObject();
  }

  if (v.isUndefined()) {
    return nullptr;
  }

  js::ExpandoAndGeneration* expandoAndGeneration =
    static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
  v = expandoAndGeneration->expando;
  return v.isUndefined() ? nullptr : &v.toObject();
}
Esempio n. 7
0
// static
JSObject* DOMProxyHandler::EnsureExpandoObject(JSContext* cx,
                                               JS::Handle<JSObject*> obj) {
  CheckDOMProxy(obj);

  JS::Value v = js::GetProxyPrivate(obj);
  if (v.isObject()) {
    CheckExpandoObject(obj, v);
    return &v.toObject();
  }

  js::ExpandoAndGeneration* expandoAndGeneration;
  if (!v.isUndefined()) {
    expandoAndGeneration =
        static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
    CheckExpandoAndGeneration(obj, expandoAndGeneration);
    if (expandoAndGeneration->expando.isObject()) {
      return &expandoAndGeneration->expando.toObject();
    }
  } else {
    expandoAndGeneration = nullptr;
  }

  JS::Rooted<JSObject*> expando(
      cx, JS_NewObjectWithGivenProto(cx, nullptr, nullptr));
  if (!expando) {
    return nullptr;
  }

  nsISupports* native = UnwrapDOMObject<nsISupports>(obj);
  nsWrapperCache* cache;
  CallQueryInterface(native, &cache);
  cache->PreserveWrapper(native);

  if (expandoAndGeneration) {
    expandoAndGeneration->expando.setObject(*expando);
    return expando;
  }

  js::SetProxyPrivate(obj, ObjectValue(*expando));

  return expando;
}
Esempio n. 8
0
// static
JSObject* DOMProxyHandler::GetExpandoObject(JSObject* obj) {
  CheckDOMProxy(obj);

  JS::Value v = js::GetProxyPrivate(obj);
  if (v.isObject()) {
    CheckExpandoObject(obj, v);
    return &v.toObject();
  }

  if (v.isUndefined()) {
    return nullptr;
  }

  js::ExpandoAndGeneration* expandoAndGeneration =
      static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
  CheckExpandoAndGeneration(obj, expandoAndGeneration);

  v = expandoAndGeneration->expando;
  return v.isUndefined() ? nullptr : &v.toObject();
}
Esempio n. 9
0
// static
JSObject*
DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj)
{
  MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
  JS::Value v = js::GetProxyPrivate(obj);
  if (v.isUndefined()) {
    return nullptr;
  }

  if (v.isObject()) {
    js::SetProxyPrivate(obj, UndefinedValue());
  } else {
    js::ExpandoAndGeneration* expandoAndGeneration =
      static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
    v = expandoAndGeneration->expando;
    if (v.isUndefined()) {
      return nullptr;
    }
    // We have to expose v to active JS here.  The reason for that is that we
    // might be in the middle of a GC right now.  If our proxy hasn't been
    // traced yet, when it _does_ get traced it won't trace the expando, since
    // we're breaking that link.  But the Rooted we're presumably being placed
    // into is also not going to trace us, because Rooted marking is done at
    // the very beginning of the GC.  In that situation, we need to manually
    // mark the expando as live here.  JS::ExposeValueToActiveJS will do just
    // that for us.
    //
    // We don't need to do this in the non-expandoAndGeneration case, because
    // in that case our value is stored in a slot and slots will already mark
    // the old thing live when the value in the slot changes.
    JS::ExposeValueToActiveJS(v);
    expandoAndGeneration->expando = UndefinedValue();
  }


  return &v.toObject();
}
Esempio n. 10
0
// static
JSObject* DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj) {
  CheckDOMProxy(obj);

  JS::Value v = js::GetProxyPrivate(obj);
  if (v.isUndefined()) {
    return nullptr;
  }

  if (v.isObject()) {
    js::SetProxyPrivate(obj, UndefinedValue());
  } else {
    js::ExpandoAndGeneration* expandoAndGeneration =
        static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
    v = expandoAndGeneration->expando;
    if (v.isUndefined()) {
      return nullptr;
    }
    expandoAndGeneration->expando = UndefinedValue();
  }

  CheckExpandoObject(obj, v);

  return &v.toObject();
}
// Define a shadowing property on |this| for the XBL field defined by the
// contents of the callee's reserved slots.  If the property was defined,
// *installed will be true, and idp will be set to the property name that was
// defined.
static bool
InstallXBLField(JSContext* cx,
                JS::Handle<JSObject*> callee, JS::Handle<JSObject*> thisObj,
                JS::MutableHandle<jsid> idp, bool* installed)
{
  *installed = false;

  // First ensure |this| is a reasonable XBL bound node.
  //
  // FieldAccessorGuard already determined whether |thisObj| was acceptable as
  // |this| in terms of not throwing a TypeError.  Assert this for good measure.
  MOZ_ASSERT(ValueHasISupportsPrivate(JS::ObjectValue(*thisObj)));

  // But there are some cases where we must accept |thisObj| but not install a
  // property on it, or otherwise touch it.  Hence this split of |this|-vetting
  // duties.
  nsISupports* native =
    nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, thisObj);
  if (!native) {
    // Looks like whatever |thisObj| is it's not our nsIContent.  It might well
    // be the proto our binding installed, however, where the private is the
    // nsXBLDocumentInfo, so just baul out quietly.  Do NOT throw an exception
    // here.
    //
    // We could make this stricter by checking the class maybe, but whatever.
    return true;
  }

  nsCOMPtr<nsIContent> xblNode = do_QueryInterface(native);
  if (!xblNode) {
    xpc::Throw(cx, NS_ERROR_UNEXPECTED);
    return false;
  }

  // Now that |this| is okay, actually install the field.

  // Because of the possibility (due to XBL binding inheritance, because each
  // XBL binding lives in its own global object) that |this| might be in a
  // different compartment from the callee (not to mention that this method can
  // be called with an arbitrary |this| regardless of how insane XBL is), and
  // because in this method we've entered |this|'s compartment (see in
  // Field[GS]etter where we attempt a cross-compartment call), we must enter
  // the callee's compartment to access its reserved slots.
  nsXBLPrototypeBinding* protoBinding;
  nsDependentJSString fieldName;
  {
    JSAutoCompartment ac(cx, callee);

    JS::Rooted<JSObject*> xblProto(cx);
    xblProto = &js::GetFunctionNativeReserved(callee, XBLPROTO_SLOT).toObject();

    JS::Rooted<JS::Value> name(cx, js::GetFunctionNativeReserved(callee, FIELD_SLOT));
    JSFlatString* fieldStr = JS_ASSERT_STRING_IS_FLAT(name.toString());
    fieldName.init(fieldStr);

    MOZ_ALWAYS_TRUE(JS_ValueToId(cx, name, idp.address()));

    // If a separate XBL scope is being used, the callee is not same-compartment
    // with the xbl prototype, and the object is a cross-compartment wrapper.
    xblProto = js::UncheckedUnwrap(xblProto);
    JSAutoCompartment ac2(cx, xblProto);
    JS::Value slotVal = ::JS_GetReservedSlot(xblProto, 0);
    protoBinding = static_cast<nsXBLPrototypeBinding*>(slotVal.toPrivate());
    MOZ_ASSERT(protoBinding);
  }

  nsXBLProtoImplField* field = protoBinding->FindField(fieldName);
  MOZ_ASSERT(field);

  // This mirrors code in nsXBLProtoImpl::InstallImplementation
  nsCOMPtr<nsIScriptGlobalObject> global =
    do_QueryInterface(xblNode->OwnerDoc()->GetWindow());
  if (!global) {
    return true;
  }

  nsCOMPtr<nsIScriptContext> context = global->GetContext();
  if (!context) {
    return true;
  }

  nsresult rv = field->InstallField(context, thisObj, protoBinding->DocURI(),
                                    installed);
  if (NS_SUCCEEDED(rv)) {
    return true;
  }

  if (!::JS_IsExceptionPending(cx)) {
    xpc::Throw(cx, rv);
  }
  return false;
}