tor-browser

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

ChromeScriptLoader.cpp (18802B)


      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 "PrecompiledScript.h"
      8 
      9 #include "nsIIncrementalStreamLoader.h"
     10 #include "nsIURI.h"
     11 #include "nsIChannel.h"
     12 #include "nsNetUtil.h"
     13 #include "nsThreadUtils.h"
     14 
     15 #include "jsapi.h"
     16 #include "jsfriendapi.h"
     17 #include "js/CompileOptions.h"  // JS::CompileOptions, JS::OwningCompileOptions
     18 #include "js/CompilationAndEvaluation.h"
     19 #include "js/experimental/CompileScript.h"  // JS::CompileGlobalScriptToStencil, JS::NewFrontendContext, JS::DestroyFrontendContext, JS::SetNativeStackQuota, JS::ThreadStackQuotaForSize, JS::HadFrontendErrors, JS::ConvertFrontendErrorsToRuntimeErrors
     20 #include "js/experimental/JSStencil.h"  // JS::Stencil, JS::CompileGlobalScriptToStencil, JS::InstantiateGlobalStencil
     21 #include "js/SourceText.h"  // JS::SourceText
     22 #include "js/Utility.h"
     23 
     24 #include "mozilla/AlreadyAddRefed.h"  // already_AddRefed
     25 #include "mozilla/Assertions.h"       // MOZ_ASSERT
     26 #include "mozilla/Attributes.h"
     27 #include "mozilla/ClearOnShutdown.h"  // RunOnShutdown
     28 #include "mozilla/EventQueue.h"       // EventQueuePriority
     29 #include "mozilla/Mutex.h"
     30 #include "mozilla/SchedulerGroup.h"
     31 #include "mozilla/StaticMutex.h"
     32 #include "mozilla/StaticPrefs_javascript.h"
     33 #include "mozilla/dom/ChromeUtils.h"
     34 #include "mozilla/dom/Promise.h"
     35 #include "mozilla/dom/ScriptLoader.h"
     36 #include "mozilla/HoldDropJSObjects.h"
     37 #include "mozilla/RefPtr.h"          // RefPtr
     38 #include "mozilla/TaskController.h"  // TaskController, Task
     39 #include "mozilla/ThreadSafety.h"    // MOZ_GUARDED_BY
     40 #include "mozilla/Utf8.h"            // Utf8Unit
     41 #include "mozilla/Vector.h"
     42 #include "nsCCUncollectableMarker.h"
     43 #include "nsCycleCollectionParticipant.h"
     44 
     45 using namespace JS;
     46 using namespace mozilla;
     47 using namespace mozilla::dom;
     48 
     49 class AsyncScriptCompileTask final : public Task {
     50  static mozilla::StaticMutex sOngoingTasksMutex;
     51  static Vector<AsyncScriptCompileTask*> sOngoingTasks
     52      MOZ_GUARDED_BY(sOngoingTasksMutex);
     53  static bool sIsShutdownRegistered;
     54 
     55  // Compilation tasks should be cancelled before calling JS_ShutDown, in order
     56  // to avoid keeping JS::Stencil and SharedImmutableString pointers alive
     57  // beyond it.
     58  //
     59  // Cancel all ongoing tasks at ShutdownPhase::XPCOMShutdownFinal, which
     60  // happens before calling JS_ShutDown.
     61  static bool RegisterTask(AsyncScriptCompileTask* aTask) {
     62    MOZ_ASSERT(NS_IsMainThread());
     63 
     64    if (!sIsShutdownRegistered) {
     65      sIsShutdownRegistered = true;
     66 
     67      RunOnShutdown([] {
     68        StaticMutexAutoLock lock(sOngoingTasksMutex);
     69        for (auto* task : sOngoingTasks) {
     70          task->Cancel();
     71        }
     72      });
     73    }
     74 
     75    StaticMutexAutoLock lock(sOngoingTasksMutex);
     76    return sOngoingTasks.append(aTask);
     77  }
     78 
     79  static void UnregisterTask(const AsyncScriptCompileTask* aTask) {
     80    StaticMutexAutoLock lock(sOngoingTasksMutex);
     81    sOngoingTasks.eraseIfEqual(aTask);
     82  }
     83 
     84 public:
     85  explicit AsyncScriptCompileTask(JS::SourceText<Utf8Unit>&& aSrcBuf)
     86      : Task(Kind::OffMainThreadOnly, EventQueuePriority::Normal),
     87        mOptions(JS::OwningCompileOptions::ForFrontendContext()),
     88        mSrcBuf(std::move(aSrcBuf)),
     89        mMutex("AsyncScriptCompileTask") {}
     90 
     91  ~AsyncScriptCompileTask() {
     92    if (mFrontendContext) {
     93      JS::DestroyFrontendContext(mFrontendContext);
     94    }
     95    UnregisterTask(this);
     96  }
     97 
     98  bool Init(const JS::OwningCompileOptions& aOptions) {
     99    if (!RegisterTask(this)) {
    100      return false;
    101    }
    102 
    103    mFrontendContext = JS::NewFrontendContext();
    104    if (!mFrontendContext) {
    105      return false;
    106    }
    107 
    108    if (!mOptions.copy(mFrontendContext, aOptions)) {
    109      return false;
    110    }
    111 
    112    return true;
    113  }
    114 
    115 private:
    116  void Compile() {
    117    // NOTE: The stack limit must be set from the same thread that compiles.
    118    size_t stackSize = TaskController::GetThreadStackSize();
    119    JS::SetNativeStackQuota(mFrontendContext,
    120                            JS::ThreadStackQuotaForSize(stackSize));
    121 
    122    mStencil =
    123        JS::CompileGlobalScriptToStencil(mFrontendContext, mOptions, mSrcBuf);
    124  }
    125 
    126  // Cancel the task.
    127  // If the task is already running, this waits for the task to finish.
    128  void Cancel() {
    129    MOZ_ASSERT(NS_IsMainThread());
    130 
    131    MutexAutoLock lock(mMutex);
    132 
    133    mIsCancelled = true;
    134 
    135    mStencil = nullptr;
    136  }
    137 
    138 public:
    139  TaskResult Run() override {
    140    MutexAutoLock lock(mMutex);
    141 
    142    if (mIsCancelled) {
    143      return TaskResult::Complete;
    144    }
    145 
    146    Compile();
    147    return TaskResult::Complete;
    148  }
    149 
    150  already_AddRefed<JS::Stencil> StealStencil(JSContext* aCx) {
    151    JS::FrontendContext* fc = mFrontendContext;
    152    mFrontendContext = nullptr;
    153 
    154    MOZ_ASSERT(fc);
    155 
    156    if (JS::HadFrontendErrors(fc)) {
    157      (void)JS::ConvertFrontendErrorsToRuntimeErrors(aCx, fc, mOptions);
    158      JS::DestroyFrontendContext(fc);
    159      return nullptr;
    160    }
    161 
    162    // Report warnings.
    163    if (!JS::ConvertFrontendErrorsToRuntimeErrors(aCx, fc, mOptions)) {
    164      JS::DestroyFrontendContext(fc);
    165      return nullptr;
    166    }
    167 
    168    JS::DestroyFrontendContext(fc);
    169 
    170    return mStencil.forget();
    171  }
    172 
    173 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
    174  bool GetName(nsACString& aName) override {
    175    aName.AssignLiteral("AsyncScriptCompileTask");
    176    return true;
    177  }
    178 #endif
    179 
    180 private:
    181  // Owning-pointer for the context associated with the script compilation.
    182  //
    183  // The context is allocated on main thread in Init method, and is freed on
    184  // any thread in the destructor.
    185  JS::FrontendContext* mFrontendContext = nullptr;
    186 
    187  JS::OwningCompileOptions mOptions;
    188 
    189  RefPtr<JS::Stencil> mStencil;
    190 
    191  JS::SourceText<Utf8Unit> mSrcBuf;
    192 
    193  // This mutex is locked during running the task or cancelling task.
    194  mozilla::Mutex mMutex;
    195 
    196  bool mIsCancelled MOZ_GUARDED_BY(mMutex) = false;
    197 };
    198 
    199 /* static */ mozilla::StaticMutex AsyncScriptCompileTask::sOngoingTasksMutex;
    200 MOZ_RUNINIT /* static */ Vector<AsyncScriptCompileTask*>
    201    AsyncScriptCompileTask::sOngoingTasks;
    202 /* static */ bool AsyncScriptCompileTask::sIsShutdownRegistered = false;
    203 
    204 class AsyncScriptCompiler;
    205 
    206 class AsyncScriptCompilationCompleteTask : public Task {
    207 public:
    208  AsyncScriptCompilationCompleteTask(AsyncScriptCompiler* aCompiler,
    209                                     AsyncScriptCompileTask* aCompileTask)
    210      : Task(Kind::MainThreadOnly, EventQueuePriority::Normal),
    211        mCompiler(aCompiler),
    212        mCompileTask(aCompileTask) {
    213    MOZ_ASSERT(NS_IsMainThread());
    214  }
    215 
    216 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
    217  bool GetName(nsACString& aName) override {
    218    aName.AssignLiteral("AsyncScriptCompilationCompleteTask");
    219    return true;
    220  }
    221 #endif
    222 
    223  TaskResult Run() override;
    224 
    225 private:
    226  // NOTE:
    227  // This field is main-thread only, and this task shouldn't be freed off
    228  // main thread.
    229  //
    230  // This is guaranteed by not having off-thread tasks which depends on this
    231  // task, because otherwise the off-thread task's mDependencies can be the
    232  // last reference, which results in freeing this task off main thread.
    233  //
    234  // If such task is added, this field must be moved to separate storage.
    235  RefPtr<AsyncScriptCompiler> mCompiler;
    236 
    237  RefPtr<AsyncScriptCompileTask> mCompileTask;
    238 };
    239 
    240 class AsyncScriptCompiler final : public nsIIncrementalStreamLoaderObserver {
    241 public:
    242  // Note: References to this class are never held by cycle-collected objects.
    243  // If at any point a reference is returned to a caller, please update this
    244  // class to implement cycle collection.
    245  NS_DECL_ISUPPORTS
    246  NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
    247 
    248  AsyncScriptCompiler(JSContext* aCx, nsIGlobalObject* aGlobal,
    249                      const nsACString& aURL, Promise* aPromise)
    250      : mOptions(aCx),
    251        mURL(aURL),
    252        mGlobalObject(aGlobal),
    253        mPromise(aPromise),
    254        mScriptLength(0) {}
    255 
    256  [[nodiscard]] nsresult Start(JSContext* aCx,
    257                               const CompileScriptOptionsDictionary& aOptions,
    258                               nsIPrincipal* aPrincipal);
    259 
    260  void OnCompilationComplete(AsyncScriptCompileTask* aCompileTask);
    261 
    262 protected:
    263  virtual ~AsyncScriptCompiler() {
    264    if (mPromise->State() == Promise::PromiseState::Pending) {
    265      mPromise->MaybeReject(NS_ERROR_FAILURE);
    266    }
    267  }
    268 
    269 private:
    270  void Reject(JSContext* aCx);
    271  void Reject(JSContext* aCx, const char* aMxg);
    272 
    273  bool StartCompile(JSContext* aCx);
    274  bool StartOffThreadCompile(JS::SourceText<Utf8Unit>&& aSrcBuf);
    275  void FinishCompile(JSContext* aCx);
    276  void Finish(JSContext* aCx, RefPtr<JS::Stencil>&& aStencil);
    277 
    278  OwningCompileOptions mOptions;
    279  nsCString mURL;
    280  nsCOMPtr<nsIGlobalObject> mGlobalObject;
    281  RefPtr<Promise> mPromise;
    282  nsString mCharset;
    283  UniquePtr<Utf8Unit[], JS::FreePolicy> mScriptText;
    284  size_t mScriptLength;
    285 };
    286 
    287 NS_IMPL_ISUPPORTS(AsyncScriptCompiler, nsIIncrementalStreamLoaderObserver)
    288 
    289 nsresult AsyncScriptCompiler::Start(
    290    JSContext* aCx, const CompileScriptOptionsDictionary& aOptions,
    291    nsIPrincipal* aPrincipal) {
    292  mCharset = aOptions.mCharset;
    293 
    294  CompileOptions options(aCx);
    295  nsAutoCString filename;
    296  if (aOptions.mFilename.WasPassed()) {
    297    filename = NS_ConvertUTF16toUTF8(aOptions.mFilename.Value());
    298    options.setFile(filename.get());
    299  } else {
    300    options.setFile(mURL.get());
    301  }
    302  options.setNoScriptRval(!aOptions.mHasReturnValue);
    303 
    304  if (!aOptions.mLazilyParse) {
    305    options.setForceFullParse();
    306  }
    307 
    308  if (NS_WARN_IF(!mOptions.copy(aCx, options))) {
    309    return NS_ERROR_OUT_OF_MEMORY;
    310  }
    311 
    312  nsCOMPtr<nsIURI> uri;
    313  nsresult rv = NS_NewURI(getter_AddRefs(uri), mURL);
    314  NS_ENSURE_SUCCESS(rv, rv);
    315 
    316  nsCOMPtr<nsIChannel> channel;
    317  rv = NS_NewChannel(
    318      getter_AddRefs(channel), uri, aPrincipal,
    319      nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
    320      nsIContentPolicy::TYPE_INTERNAL_CHROMEUTILS_COMPILED_SCRIPT);
    321  NS_ENSURE_SUCCESS(rv, rv);
    322 
    323  // allow deprecated HTTP request from SystemPrincipal
    324  nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
    325  loadInfo->SetAllowDeprecatedSystemRequests(true);
    326  nsCOMPtr<nsIIncrementalStreamLoader> loader;
    327  rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), this);
    328  NS_ENSURE_SUCCESS(rv, rv);
    329 
    330  return channel->AsyncOpen(loader);
    331 }
    332 
    333 bool AsyncScriptCompiler::StartCompile(JSContext* aCx) {
    334  JS::SourceText<Utf8Unit> srcBuf;
    335  if (!srcBuf.init(aCx, std::move(mScriptText), mScriptLength)) {
    336    return false;
    337  }
    338 
    339  // TODO: This uses the same heuristics and the same threshold as the
    340  //       JS::CanCompileOffThread, but the heuristics needs to be updated to
    341  //       reflect the change regarding the Stencil API, and also the thread
    342  //       management on the consumer side (bug 1846388).
    343  static constexpr size_t OffThreadMinimumTextLength = 5 * 1000;
    344 
    345  if (StaticPrefs::javascript_options_parallel_parsing() &&
    346      mScriptLength >= OffThreadMinimumTextLength) {
    347    if (!StartOffThreadCompile(std::move(srcBuf))) {
    348      return false;
    349    }
    350    return true;
    351  }
    352 
    353  RefPtr<Stencil> stencil =
    354      JS::CompileGlobalScriptToStencil(aCx, mOptions, srcBuf);
    355  if (!stencil) {
    356    return false;
    357  }
    358 
    359  Finish(aCx, std::move(stencil));
    360  return true;
    361 }
    362 
    363 bool AsyncScriptCompiler::StartOffThreadCompile(
    364    JS::SourceText<Utf8Unit>&& aSrcBuf) {
    365  RefPtr<AsyncScriptCompileTask> compileTask =
    366      new AsyncScriptCompileTask(std::move(aSrcBuf));
    367 
    368  RefPtr<AsyncScriptCompilationCompleteTask> complationCompleteTask =
    369      new AsyncScriptCompilationCompleteTask(this, compileTask.get());
    370 
    371  if (!compileTask->Init(mOptions)) {
    372    return false;
    373  }
    374 
    375  complationCompleteTask->AddDependency(compileTask.get());
    376 
    377  TaskController::Get()->AddTask(compileTask.forget());
    378  TaskController::Get()->AddTask(complationCompleteTask.forget());
    379  return true;
    380 }
    381 
    382 Task::TaskResult AsyncScriptCompilationCompleteTask::Run() {
    383  mCompiler->OnCompilationComplete(mCompileTask.get());
    384  mCompiler = nullptr;
    385  mCompileTask = nullptr;
    386  return TaskResult::Complete;
    387 }
    388 
    389 void AsyncScriptCompiler::OnCompilationComplete(
    390    AsyncScriptCompileTask* aCompileTask) {
    391  AutoJSAPI jsapi;
    392  if (!jsapi.Init(mGlobalObject)) {
    393    mPromise->MaybeReject(NS_ERROR_FAILURE);
    394    return;
    395  }
    396 
    397  JSContext* cx = jsapi.cx();
    398  RefPtr<JS::Stencil> stencil = aCompileTask->StealStencil(cx);
    399  if (!stencil) {
    400    Reject(cx);
    401    return;
    402  }
    403 
    404  Finish(cx, std::move(stencil));
    405  return;
    406 }
    407 
    408 void AsyncScriptCompiler::Finish(JSContext* aCx,
    409                                 RefPtr<JS::Stencil>&& aStencil) {
    410  RefPtr<PrecompiledScript> result =
    411      new PrecompiledScript(mGlobalObject, aStencil, mOptions);
    412 
    413  mPromise->MaybeResolve(result);
    414 }
    415 
    416 void AsyncScriptCompiler::Reject(JSContext* aCx) {
    417  RootedValue value(aCx, JS::UndefinedValue());
    418  if (JS_GetPendingException(aCx, &value)) {
    419    JS_ClearPendingException(aCx);
    420  }
    421  mPromise->MaybeReject(value);
    422 }
    423 
    424 void AsyncScriptCompiler::Reject(JSContext* aCx, const char* aMsg) {
    425  nsAutoString msg;
    426  msg.AppendASCII(aMsg);
    427  msg.AppendLiteral(": ");
    428  nsDependentCString filename(mOptions.filename().c_str());
    429  AppendUTF8toUTF16(filename, msg);
    430 
    431  RootedValue exn(aCx);
    432  if (xpc::NonVoidStringToJsval(aCx, msg, &exn)) {
    433    JS_SetPendingException(aCx, exn);
    434  }
    435 
    436  Reject(aCx);
    437 }
    438 
    439 NS_IMETHODIMP
    440 AsyncScriptCompiler::OnStartRequest(nsIRequest* aRequest) { return NS_OK; }
    441 
    442 NS_IMETHODIMP
    443 AsyncScriptCompiler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
    444                                       nsISupports* aContext,
    445                                       uint32_t aDataLength,
    446                                       const uint8_t* aData,
    447                                       uint32_t* aConsumedData) {
    448  return NS_OK;
    449 }
    450 
    451 NS_IMETHODIMP
    452 AsyncScriptCompiler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
    453                                      nsISupports* aContext, nsresult aStatus,
    454                                      uint32_t aLength, const uint8_t* aBuf) {
    455  AutoJSAPI jsapi;
    456  if (!jsapi.Init(mGlobalObject)) {
    457    mPromise->MaybeReject(NS_ERROR_FAILURE);
    458    return NS_OK;
    459  }
    460 
    461  JSContext* cx = jsapi.cx();
    462 
    463  if (NS_FAILED(aStatus)) {
    464    Reject(cx, "Unable to load script");
    465    return NS_OK;
    466  }
    467 
    468  nsresult rv = ScriptLoader::ConvertToUTF8(
    469      nullptr, aBuf, aLength, mCharset, nullptr, mScriptText, mScriptLength);
    470  if (NS_FAILED(rv)) {
    471    Reject(cx, "Unable to decode script");
    472    return NS_OK;
    473  }
    474 
    475  if (!StartCompile(cx)) {
    476    Reject(cx);
    477  }
    478 
    479  return NS_OK;
    480 }
    481 
    482 namespace mozilla {
    483 namespace dom {
    484 
    485 /* static */
    486 already_AddRefed<Promise> ChromeUtils::CompileScript(
    487    GlobalObject& aGlobal, const nsAString& aURL,
    488    const CompileScriptOptionsDictionary& aOptions, ErrorResult& aRv) {
    489  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
    490  MOZ_ASSERT(global);
    491 
    492  RefPtr<Promise> promise = Promise::Create(global, aRv);
    493  if (aRv.Failed()) {
    494    return nullptr;
    495  }
    496 
    497  NS_ConvertUTF16toUTF8 url(aURL);
    498  RefPtr<AsyncScriptCompiler> compiler =
    499      new AsyncScriptCompiler(aGlobal.Context(), global, url, promise);
    500 
    501  nsresult rv = compiler->Start(aGlobal.Context(), aOptions,
    502                                aGlobal.GetSubjectPrincipal());
    503  if (NS_FAILED(rv)) {
    504    promise->MaybeReject(rv);
    505  }
    506 
    507  return promise.forget();
    508 }
    509 
    510 PrecompiledScript::PrecompiledScript(nsISupports* aParent,
    511                                     RefPtr<JS::Stencil> aStencil,
    512                                     JS::ReadOnlyCompileOptions& aOptions)
    513    : mParent(aParent),
    514      mStencil(aStencil),
    515      mPublicURL(aOptions.filename().c_str()),
    516      mHasReturnValue(!aOptions.noScriptRval) {
    517  MOZ_ASSERT(aParent);
    518  MOZ_ASSERT(aStencil);
    519 #ifdef DEBUG
    520  // AsyncScriptCompiler::Start can call JS::CompileOptions::setForceFullParse,
    521  // but it should be compatible with the default JS::InstantiateOptions.
    522  JS::InstantiateOptions options(aOptions);
    523  options.assertCompatibleWithDefault();
    524 #endif
    525 };
    526 
    527 void PrecompiledScript::ExecuteInGlobal(JSContext* aCx, HandleObject aGlobal,
    528                                        const ExecuteInGlobalOptions& aOptions,
    529                                        MutableHandleValue aRval,
    530                                        ErrorResult& aRv) {
    531  {
    532    RootedObject targetObj(aCx, JS_FindCompilationScope(aCx, aGlobal));
    533    // Use AutoEntryScript for its ReportException method call.
    534    // This will ensure notified any exception happening in the content script
    535    // directly to the console, so that exceptions are flagged with the right
    536    // innerWindowID. It helps these exceptions to appear in the page's web
    537    // console.
    538    AutoEntryScript aes(targetObj, "pre-compiled-script execution");
    539    JSContext* cx = aes.cx();
    540 
    541    // See assertion in constructor.
    542    JS::InstantiateOptions options;
    543    Rooted<JSScript*> script(
    544        cx, JS::InstantiateGlobalStencil(cx, options, mStencil));
    545    if (!script) {
    546      aRv.NoteJSContextException(aCx);
    547      return;
    548    }
    549 
    550    if (!JS_ExecuteScript(cx, script, aRval)) {
    551      JS::RootedValue exn(cx);
    552      if (aOptions.mReportExceptions) {
    553        // Note that ReportException will consume the exception.
    554        aes.ReportException();
    555      } else {
    556        // Set the exception on our caller's cx.
    557        aRv.MightThrowJSException();
    558        aRv.StealExceptionFromJSContext(cx);
    559      }
    560      return;
    561    }
    562  }
    563 
    564  JS_WrapValue(aCx, aRval);
    565 }
    566 
    567 void PrecompiledScript::GetUrl(nsAString& aUrl) {
    568  CopyUTF8toUTF16(mPublicURL, aUrl);
    569 }
    570 
    571 bool PrecompiledScript::HasReturnValue() { return mHasReturnValue; }
    572 
    573 JSObject* PrecompiledScript::WrapObject(JSContext* aCx,
    574                                        HandleObject aGivenProto) {
    575  return PrecompiledScript_Binding::Wrap(aCx, this, aGivenProto);
    576 }
    577 
    578 bool PrecompiledScript::IsBlackForCC(bool aTracingNeeded) {
    579  return (nsCCUncollectableMarker::sGeneration && HasKnownLiveWrapper() &&
    580          (!aTracingNeeded || HasNothingToTrace(this)));
    581 }
    582 
    583 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PrecompiledScript, mParent)
    584 
    585 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PrecompiledScript)
    586  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    587  NS_INTERFACE_MAP_ENTRY(nsISupports)
    588 NS_INTERFACE_MAP_END
    589 
    590 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(PrecompiledScript)
    591  return tmp->IsBlackForCC(false);
    592 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
    593 
    594 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(PrecompiledScript)
    595  return tmp->IsBlackForCC(true);
    596 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
    597 
    598 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(PrecompiledScript)
    599  return tmp->IsBlackForCC(false);
    600 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
    601 
    602 NS_IMPL_CYCLE_COLLECTING_ADDREF(PrecompiledScript)
    603 NS_IMPL_CYCLE_COLLECTING_RELEASE(PrecompiledScript)
    604 
    605 }  // namespace dom
    606 }  // namespace mozilla