tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SimpleGlobalObject.cpp (5980B)


      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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/SimpleGlobalObject.h"
      8 
      9 #include "js/Class.h"
     10 #include "js/Object.h"  // JS::GetClass, JS::GetObjectISupports, JS::SetObjectISupports
     11 #include "jsapi.h"
     12 #include "mozilla/NullPrincipal.h"
     13 #include "mozilla/dom/ScriptSettings.h"
     14 #include "nsContentUtils.h"
     15 #include "nsJSPrincipals.h"
     16 #include "nsThreadUtils.h"
     17 #include "xpcprivate.h"
     18 
     19 namespace mozilla::dom {
     20 
     21 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(SimpleGlobalObject)
     22 
     23 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SimpleGlobalObject)
     24  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     25  tmp->UnlinkObjectsInGlobal();
     26 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     27 
     28 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SimpleGlobalObject)
     29  tmp->TraverseObjectsInGlobal(cb);
     30 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     31 
     32 NS_IMPL_CYCLE_COLLECTING_ADDREF(SimpleGlobalObject)
     33 NS_IMPL_CYCLE_COLLECTING_RELEASE(SimpleGlobalObject)
     34 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SimpleGlobalObject)
     35  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     36  NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
     37 NS_INTERFACE_MAP_END
     38 
     39 static SimpleGlobalObject* GetSimpleGlobal(JSObject* global);
     40 
     41 static void SimpleGlobal_finalize(JS::GCContext* gcx, JSObject* obj) {
     42  SimpleGlobalObject* globalObject = GetSimpleGlobal(obj);
     43  if (globalObject) {
     44    globalObject->ClearWrapper(obj);
     45    NS_RELEASE(globalObject);
     46  }
     47 }
     48 
     49 static size_t SimpleGlobal_moved(JSObject* obj, JSObject* old) {
     50  SimpleGlobalObject* globalObject = GetSimpleGlobal(obj);
     51  if (globalObject) {
     52    globalObject->UpdateWrapper(obj, old);
     53  }
     54  return 0;
     55 }
     56 
     57 static const JSClassOps SimpleGlobalClassOps = {
     58    nullptr,
     59    nullptr,
     60    nullptr,
     61    JS_NewEnumerateStandardClasses,
     62    JS_ResolveStandardClass,
     63    JS_MayResolveStandardClass,
     64    SimpleGlobal_finalize,
     65    nullptr,
     66    nullptr,
     67    JS_GlobalObjectTraceHook,
     68 };
     69 
     70 static const js::ClassExtension SimpleGlobalClassExtension = {
     71    SimpleGlobal_moved};
     72 
     73 static_assert(JSCLASS_GLOBAL_APPLICATION_SLOTS > 0,
     74              "Need at least one slot for JSCLASS_SLOT0_IS_NSISUPPORTS");
     75 
     76 const JSClass SimpleGlobalClass = {"",
     77                                   JSCLASS_GLOBAL_FLAGS |
     78                                       JSCLASS_SLOT0_IS_NSISUPPORTS |
     79                                       JSCLASS_FOREGROUND_FINALIZE,
     80                                   &SimpleGlobalClassOps,
     81                                   JS_NULL_CLASS_SPEC,
     82                                   &SimpleGlobalClassExtension,
     83                                   JS_NULL_OBJECT_OPS};
     84 
     85 static SimpleGlobalObject* GetSimpleGlobal(JSObject* global) {
     86  MOZ_ASSERT(JS::GetClass(global) == &SimpleGlobalClass);
     87 
     88  return JS::GetObjectISupports<SimpleGlobalObject>(global);
     89 }
     90 
     91 // static
     92 JSObject* SimpleGlobalObject::Create(GlobalType globalType,
     93                                     JS::Handle<JS::Value> proto) {
     94  // We can't root our return value with our AutoJSAPI because the rooting
     95  // analysis thinks ~AutoJSAPI can GC.  So we need to root in a scope outside
     96  // the lifetime of the AutoJSAPI.
     97  JS::Rooted<JSObject*> global(RootingCx());
     98 
     99  {  // Scope to ensure the AutoJSAPI destructor runs before we end up returning
    100    AutoJSAPI jsapi;
    101    jsapi.Init();
    102    JSContext* cx = jsapi.cx();
    103 
    104    JS::RealmOptions options;
    105    options.creationOptions()
    106        .setInvisibleToDebugger(true)
    107        // Put our SimpleGlobalObjects in the system zone, so we won't create
    108        // lots of zones for what are probably very short-lived
    109        // compartments.  This should help them be GCed quicker and take up
    110        // less memory before they're GCed.
    111        .setNewCompartmentInSystemZone();
    112 
    113    if (NS_IsMainThread()) {
    114      nsCOMPtr<nsIPrincipal> principal =
    115          NullPrincipal::CreateWithoutOriginAttributes();
    116      options.creationOptions().setTrace(xpc::TraceXPCGlobal);
    117      global = xpc::CreateGlobalObject(cx, &SimpleGlobalClass,
    118                                       nsJSPrincipals::get(principal), options);
    119    } else {
    120      global = JS_NewGlobalObject(cx, &SimpleGlobalClass, nullptr,
    121                                  JS::DontFireOnNewGlobalHook, options);
    122    }
    123 
    124    if (!global) {
    125      jsapi.ClearException();
    126      return nullptr;
    127    }
    128 
    129    JSAutoRealm ar(cx, global);
    130 
    131    // It's important to create the nsIGlobalObject for our new global before we
    132    // start trying to wrap things like the prototype into its compartment,
    133    // because the wrap operation relies on the global having its
    134    // nsIGlobalObject already.
    135    RefPtr<SimpleGlobalObject> globalObject =
    136        new SimpleGlobalObject(global, globalType);
    137 
    138    JS::SetRealmReduceTimerPrecisionCallerType(
    139        js::GetNonCCWObjectRealm(global),
    140        RTPCallerTypeToToken(globalObject->GetRTPCallerType()));
    141 
    142    // Pass on ownership of globalObject to |global|.
    143    JS::SetObjectISupports(global, globalObject.forget().take());
    144 
    145    if (proto.isObjectOrNull()) {
    146      JS::Rooted<JSObject*> protoObj(cx, proto.toObjectOrNull());
    147      if (!JS_WrapObject(cx, &protoObj)) {
    148        jsapi.ClearException();
    149        return nullptr;
    150      }
    151 
    152      if (!JS_SetPrototype(cx, global, protoObj)) {
    153        jsapi.ClearException();
    154        return nullptr;
    155      }
    156    } else if (!proto.isUndefined()) {
    157      // Bogus proto.
    158      return nullptr;
    159    }
    160 
    161    JS_FireOnNewGlobalObject(cx, global);
    162  }
    163 
    164  return global;
    165 }
    166 
    167 // static
    168 SimpleGlobalObject::GlobalType SimpleGlobalObject::SimpleGlobalType(
    169    JSObject* obj) {
    170  if (JS::GetClass(obj) != &SimpleGlobalClass) {
    171    return SimpleGlobalObject::GlobalType::NotSimpleGlobal;
    172  }
    173 
    174  SimpleGlobalObject* globalObject = GetSimpleGlobal(obj);
    175  return globalObject->Type();
    176 }
    177 
    178 }  // namespace mozilla::dom