<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/memory_details.h"
#include <psapi.h>

#include "base/file_version_info.h"
#include "base/histogram.h"
#include "base/image_util.h"
#include "base/message_loop.h"
#include "base/process_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_trial.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/render_process_host.h"
#include "chrome/browser/render_view_host.h"
#include "chrome/browser/tab_contents.h"
#include "chrome/browser/web_contents.h"

class RenderViewHostDelegate;

// Template of static data we use for finding browser process information.
// These entries must match the ordering for MemoryDetails::BrowserProcess.
static ProcessData g_process_template[] = {
    { L"Chromium", L"chrome.exe", },
    { L"IE", L"iexplore.exe", },
    { L"Firefox", L"firefox.exe", },
    { L"Opera", L"opera.exe", },
    { L"Safari", L"safari.exe", },
  };

// About threading:
//
// This operation will hit no fewer than 3 threads.
//
// The PluginHostIterator can only be accessed from the IO thread.
//
// The RenderProcessHostIterator can only be accessed from the UI thread.
//
// This operation can take 30-100ms to complete.  We never want to have
// one task run for that long on the UI or IO threads.  So, we run the
// expensive parts of this operation over on the file thread.
//

MemoryDetails::MemoryDetails()
  : ui_loop_(NULL) {
  for (int index = 0; index < arraysize(g_process_template); ++index) {
    process_data_[index].name = g_process_template[index].name;
    process_data_[index].process_name = g_process_template[index].process_name;
  }
}

void MemoryDetails::StartFetch() {
  ui_loop_ = MessageLoop::current();

  DCHECK(ui_loop_ != g_browser_process->io_thread()->message_loop());
  DCHECK(ui_loop_ != g_browser_process->file_thread()->message_loop());

  // In order to process this request, we need to use the plugin information.
  // However, plugin process information is only available from the IO thread.
  g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
      NewRunnableMethod(this, &MemoryDetails::CollectPluginInformation));
}

void MemoryDetails::CollectPluginInformation() {
  DCHECK(MessageLoop::current() ==
      ChromeThread::GetMessageLoop(ChromeThread::IO));

  // Collect the list of plugins.
  for (PluginProcessHostIterator plugin_iter;
       !plugin_iter.Done(); ++plugin_iter) {
    PluginProcessHost* plugin = const_cast<PluginProcessHost*>(*plugin_iter);
    DCHECK(plugin);
    if (!plugin || !plugin->process())
      continue;

    PluginProcessInformation info;
    info.pid = process_util::GetProcId(plugin->process());
    if (info.pid != 0) {
      info.dll_path = plugin->dll_path();
      plugins_.push_back(info);
    }
  }

  // Now go do expensive memory lookups from the file thread.
  ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask(FROM_HERE,
      NewRunnableMethod(this, &MemoryDetails::CollectProcessData));
}

void MemoryDetails::CollectProcessData() {
  DCHECK(MessageLoop::current() ==
      ChromeThread::GetMessageLoop(ChromeThread::FILE));

  int array_size = 32;
  DWORD* process_list = NULL;
  DWORD bytes_used = 0;
  do {
    array_size *= 2;
    process_list = static_cast<DWORD*>(
        realloc(process_list, sizeof(*process_list) * array_size));
    // EnumProcesses doesn't return an error if the array is too small.
    // We have to check if the return buffer is full, and if so, call it
    // again.  See msdn docs for more info.
    if (!EnumProcesses(process_list, array_size * sizeof(*process_list),
                       &bytes_used)) {
      LOG(ERROR) << "EnumProcesses failed: " << GetLastError();
      return;
    }
  } while (bytes_used == (array_size * sizeof(*process_list)));

  int num_processes = bytes_used / sizeof(*process_list);

  // Clear old data.
  for (int index = 0; index < arraysize(g_process_template); index++)
    process_data_[index].processes.clear();

  for (int index = 0; index < num_processes; index++) {
    HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                                FALSE, process_list[index]);
    if (handle) {
      TCHAR name[MAX_PATH];
      if (GetModuleBaseName(handle, NULL, name, MAX_PATH-1)) {
        for (int index2 = 0; index2 < arraysize(g_process_template); index2++) {
          if (_wcsicmp(process_data_[index2].process_name, name) == 0) {
            // Get Memory Information.
            ProcessMemoryInformation info;
            info.pid = process_list[index];
            scoped_ptr<process_util::ProcessMetrics> metrics;
            metrics.reset(
              process_util::ProcessMetrics::CreateProcessMetrics(handle));
            metrics->GetCommittedKBytes(&info.committed);
            metrics->GetWorkingSetKBytes(&info.working_set);

            // Get Version Information.
            if (index2 == 0) {  // Chrome
              scoped_ptr<FileVersionInfo> version_info(
                 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
              if (version_info != NULL)
                info.version = version_info->file_version();
            } else if (GetModuleFileNameEx(handle, NULL, name, MAX_PATH-1)) {
              std::wstring str_name(name);
              scoped_ptr<FileVersionInfo> version_info(
                 FileVersionInfo::CreateFileVersionInfo(str_name));
              if (version_info != NULL) {
                info.version = version_info->product_version();
                info.product_name = version_info->product_name();
              }
            }

            // Add the process info to our list.
            process_data_[index2].processes.push_back(info);
            break;
          }
        }
      }
      CloseHandle(handle);
    }
  }
  free(process_list);

  // Finally return to the browser thread.
  ui_loop_->PostTask(FROM_HERE,
      NewRunnableMethod(this, &MemoryDetails::CollectRenderHostInformation));
}

void MemoryDetails::CollectRenderHostInformation() {
  DCHECK(MessageLoop::current() == ui_loop_);

  // Determine if this is a diagnostics-related process.  We skip all
  // diagnostics pages (e.g. "about:xxx" URLs).  Iterate the RenderProcessHosts
  // to find the tab contents.  If it is of type TAB_CONTENTS_ABOUT_UI, mark
  // the process as diagnostics related.
  for (size_t index = 0; index < process_data_[CHROME_BROWSER].processes.size();
      index++) {
    RenderProcessHost::iterator renderer_iter;
    for (renderer_iter = RenderProcessHost::begin(); renderer_iter !=
         RenderProcessHost::end(); ++renderer_iter) {
      DCHECK(renderer_iter->second);
      if (process_data_[CHROME_BROWSER].processes[index].pid ==
          renderer_iter->second->pid()) {
        // The RenderProcessHost may host multiple TabContents.  Any
        // of them which contain diagnostics information make the whole
        // process be considered a diagnostics process.
        //
        // NOTE: This is a bit dangerous.  We know that for now, listeners
        //       are always RenderWidgetHosts.  But in theory, they don't
        //       have to be.
        RenderProcessHost::listeners_iterator iter;
        for (iter = renderer_iter->second->listeners_begin();
             iter != renderer_iter->second->listeners_end(); ++iter) {
          RenderWidgetHost* widget =
              static_cast<RenderWidgetHost*>(iter->second);
          DCHECK(widget);
          if (!widget || !widget->IsRenderView())
            continue;

          RenderViewHost* host = static_cast<RenderViewHost*>(widget);
          TabContents* contents =
              static_cast<WebContents*>(host->delegate());
          DCHECK(contents);
          if (!contents)
            continue;

          if (contents->type() == TAB_CONTENTS_ABOUT_UI)
            process_data_[CHROME_BROWSER].processes[index].is_diagnostics =
                true;
        }
      }
    }
  }

  UpdateHistograms();

  OnDetailsAvailable();
}

void MemoryDetails::UpdateHistograms() {
  // Reports a set of memory metrics to UMA.
  // Memory is measured in units of 10KB.

  // If field trial is active, report results in special histograms.
  static scoped_refptr<FieldTrial> trial(
      FieldTrialList::Find(BrowserTrial::kMemoryModelFieldTrial));

  DWORD browser_pid = GetCurrentProcessId();
  ProcessData browser = process_data_[CHROME_BROWSER];
  size_t aggregate_memory = 0;
  for (size_t index = 0; index < browser.processes.size(); index++) {
    int sample = static_cast<int>(browser.processes[index].working_set.priv);
    aggregate_memory += sample;
    if (browser.processes[index].pid == browser_pid) {
      if (trial.get()) {
        if (trial->boolean_value())
          UMA_HISTOGRAM_MEMORY_KB(L"Memory.Browser_trial_high_memory", sample);
        else
          UMA_HISTOGRAM_MEMORY_KB(L"Memory.Browser_trial_med_memory", sample);
      } else {
        UMA_HISTOGRAM_MEMORY_KB(L"Memory.Browser", sample);
      }
    } else {
      bool is_plugin_process = false;
      for (size_t index2 = 0; index2 < plugins_.size(); index2++) {
        if (browser.processes[index].pid == plugins_[index2].pid) {
          UMA_HISTOGRAM_MEMORY_KB(L"Memory.Plugin", sample);
          is_plugin_process = true;
          break;
        }
      }
      if (!is_plugin_process) {
        if (trial.get()) {
          if (trial->boolean_value())
            UMA_HISTOGRAM_MEMORY_KB(L"Memory.Renderer_high_memory", sample);
          else
            UMA_HISTOGRAM_MEMORY_KB(L"Memory.Renderer_med_memory", sample);
        } else {
          UMA_HISTOGRAM_MEMORY_KB(L"Memory.Renderer", sample);
        }
      }
    }
  }
  UMA_HISTOGRAM_COUNTS_100(L"Memory.ProcessCount",
      static_cast<int>(browser.processes.size()));
  UMA_HISTOGRAM_COUNTS_100(L"Memory.PluginProcessCount",
      static_cast<int>(plugins_.size()));

  int total_sample = static_cast<int>(aggregate_memory / 1000);
  if (trial.get()) {
    if (trial->boolean_value())
      UMA_HISTOGRAM_MEMORY_MB(L"Memory.Total_trial_high_memory", total_sample);
    else
      UMA_HISTOGRAM_MEMORY_MB(L"Memory.Total_trial_med_memory", total_sample);
  } else {
    UMA_HISTOGRAM_MEMORY_MB(L"Memory.Total", total_sample);
  }
}

<commit_msg>Correct typo in histogram name (I left out the word trial)<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/memory_details.h"
#include <psapi.h>

#include "base/file_version_info.h"
#include "base/histogram.h"
#include "base/image_util.h"
#include "base/message_loop.h"
#include "base/process_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_trial.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/render_process_host.h"
#include "chrome/browser/render_view_host.h"
#include "chrome/browser/tab_contents.h"
#include "chrome/browser/web_contents.h"

class RenderViewHostDelegate;

// Template of static data we use for finding browser process information.
// These entries must match the ordering for MemoryDetails::BrowserProcess.
static ProcessData g_process_template[] = {
    { L"Chromium", L"chrome.exe", },
    { L"IE", L"iexplore.exe", },
    { L"Firefox", L"firefox.exe", },
    { L"Opera", L"opera.exe", },
    { L"Safari", L"safari.exe", },
  };

// About threading:
//
// This operation will hit no fewer than 3 threads.
//
// The PluginHostIterator can only be accessed from the IO thread.
//
// The RenderProcessHostIterator can only be accessed from the UI thread.
//
// This operation can take 30-100ms to complete.  We never want to have
// one task run for that long on the UI or IO threads.  So, we run the
// expensive parts of this operation over on the file thread.
//

MemoryDetails::MemoryDetails()
  : ui_loop_(NULL) {
  for (int index = 0; index < arraysize(g_process_template); ++index) {
    process_data_[index].name = g_process_template[index].name;
    process_data_[index].process_name = g_process_template[index].process_name;
  }
}

void MemoryDetails::StartFetch() {
  ui_loop_ = MessageLoop::current();

  DCHECK(ui_loop_ != g_browser_process->io_thread()->message_loop());
  DCHECK(ui_loop_ != g_browser_process->file_thread()->message_loop());

  // In order to process this request, we need to use the plugin information.
  // However, plugin process information is only available from the IO thread.
  g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
      NewRunnableMethod(this, &MemoryDetails::CollectPluginInformation));
}

void MemoryDetails::CollectPluginInformation() {
  DCHECK(MessageLoop::current() ==
      ChromeThread::GetMessageLoop(ChromeThread::IO));

  // Collect the list of plugins.
  for (PluginProcessHostIterator plugin_iter;
       !plugin_iter.Done(); ++plugin_iter) {
    PluginProcessHost* plugin = const_cast<PluginProcessHost*>(*plugin_iter);
    DCHECK(plugin);
    if (!plugin || !plugin->process())
      continue;

    PluginProcessInformation info;
    info.pid = process_util::GetProcId(plugin->process());
    if (info.pid != 0) {
      info.dll_path = plugin->dll_path();
      plugins_.push_back(info);
    }
  }

  // Now go do expensive memory lookups from the file thread.
  ChromeThread::GetMessageLoop(ChromeThread::FILE)->PostTask(FROM_HERE,
      NewRunnableMethod(this, &MemoryDetails::CollectProcessData));
}

void MemoryDetails::CollectProcessData() {
  DCHECK(MessageLoop::current() ==
      ChromeThread::GetMessageLoop(ChromeThread::FILE));

  int array_size = 32;
  DWORD* process_list = NULL;
  DWORD bytes_used = 0;
  do {
    array_size *= 2;
    process_list = static_cast<DWORD*>(
        realloc(process_list, sizeof(*process_list) * array_size));
    // EnumProcesses doesn't return an error if the array is too small.
    // We have to check if the return buffer is full, and if so, call it
    // again.  See msdn docs for more info.
    if (!EnumProcesses(process_list, array_size * sizeof(*process_list),
                       &bytes_used)) {
      LOG(ERROR) << "EnumProcesses failed: " << GetLastError();
      return;
    }
  } while (bytes_used == (array_size * sizeof(*process_list)));

  int num_processes = bytes_used / sizeof(*process_list);

  // Clear old data.
  for (int index = 0; index < arraysize(g_process_template); index++)
    process_data_[index].processes.clear();

  for (int index = 0; index < num_processes; index++) {
    HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                                FALSE, process_list[index]);
    if (handle) {
      TCHAR name[MAX_PATH];
      if (GetModuleBaseName(handle, NULL, name, MAX_PATH-1)) {
        for (int index2 = 0; index2 < arraysize(g_process_template); index2++) {
          if (_wcsicmp(process_data_[index2].process_name, name) == 0) {
            // Get Memory Information.
            ProcessMemoryInformation info;
            info.pid = process_list[index];
            scoped_ptr<process_util::ProcessMetrics> metrics;
            metrics.reset(
              process_util::ProcessMetrics::CreateProcessMetrics(handle));
            metrics->GetCommittedKBytes(&info.committed);
            metrics->GetWorkingSetKBytes(&info.working_set);

            // Get Version Information.
            if (index2 == 0) {  // Chrome
              scoped_ptr<FileVersionInfo> version_info(
                 FileVersionInfo::CreateFileVersionInfoForCurrentModule());
              if (version_info != NULL)
                info.version = version_info->file_version();
            } else if (GetModuleFileNameEx(handle, NULL, name, MAX_PATH-1)) {
              std::wstring str_name(name);
              scoped_ptr<FileVersionInfo> version_info(
                 FileVersionInfo::CreateFileVersionInfo(str_name));
              if (version_info != NULL) {
                info.version = version_info->product_version();
                info.product_name = version_info->product_name();
              }
            }

            // Add the process info to our list.
            process_data_[index2].processes.push_back(info);
            break;
          }
        }
      }
      CloseHandle(handle);
    }
  }
  free(process_list);

  // Finally return to the browser thread.
  ui_loop_->PostTask(FROM_HERE,
      NewRunnableMethod(this, &MemoryDetails::CollectRenderHostInformation));
}

void MemoryDetails::CollectRenderHostInformation() {
  DCHECK(MessageLoop::current() == ui_loop_);

  // Determine if this is a diagnostics-related process.  We skip all
  // diagnostics pages (e.g. "about:xxx" URLs).  Iterate the RenderProcessHosts
  // to find the tab contents.  If it is of type TAB_CONTENTS_ABOUT_UI, mark
  // the process as diagnostics related.
  for (size_t index = 0; index < process_data_[CHROME_BROWSER].processes.size();
      index++) {
    RenderProcessHost::iterator renderer_iter;
    for (renderer_iter = RenderProcessHost::begin(); renderer_iter !=
         RenderProcessHost::end(); ++renderer_iter) {
      DCHECK(renderer_iter->second);
      if (process_data_[CHROME_BROWSER].processes[index].pid ==
          renderer_iter->second->pid()) {
        // The RenderProcessHost may host multiple TabContents.  Any
        // of them which contain diagnostics information make the whole
        // process be considered a diagnostics process.
        //
        // NOTE: This is a bit dangerous.  We know that for now, listeners
        //       are always RenderWidgetHosts.  But in theory, they don't
        //       have to be.
        RenderProcessHost::listeners_iterator iter;
        for (iter = renderer_iter->second->listeners_begin();
             iter != renderer_iter->second->listeners_end(); ++iter) {
          RenderWidgetHost* widget =
              static_cast<RenderWidgetHost*>(iter->second);
          DCHECK(widget);
          if (!widget || !widget->IsRenderView())
            continue;

          RenderViewHost* host = static_cast<RenderViewHost*>(widget);
          TabContents* contents =
              static_cast<WebContents*>(host->delegate());
          DCHECK(contents);
          if (!contents)
            continue;

          if (contents->type() == TAB_CONTENTS_ABOUT_UI)
            process_data_[CHROME_BROWSER].processes[index].is_diagnostics =
                true;
        }
      }
    }
  }

  UpdateHistograms();

  OnDetailsAvailable();
}

void MemoryDetails::UpdateHistograms() {
  // Reports a set of memory metrics to UMA.
  // Memory is measured in units of 10KB.

  // If field trial is active, report results in special histograms.
  static scoped_refptr<FieldTrial> trial(
      FieldTrialList::Find(BrowserTrial::kMemoryModelFieldTrial));

  DWORD browser_pid = GetCurrentProcessId();
  ProcessData browser = process_data_[CHROME_BROWSER];
  size_t aggregate_memory = 0;
  for (size_t index = 0; index < browser.processes.size(); index++) {
    int sample = static_cast<int>(browser.processes[index].working_set.priv);
    aggregate_memory += sample;
    if (browser.processes[index].pid == browser_pid) {
      if (trial.get()) {
        if (trial->boolean_value())
          UMA_HISTOGRAM_MEMORY_KB(L"Memory.Browser_trial_high_memory", sample);
        else
          UMA_HISTOGRAM_MEMORY_KB(L"Memory.Browser_trial_med_memory", sample);
      } else {
        UMA_HISTOGRAM_MEMORY_KB(L"Memory.Browser", sample);
      }
    } else {
      bool is_plugin_process = false;
      for (size_t index2 = 0; index2 < plugins_.size(); index2++) {
        if (browser.processes[index].pid == plugins_[index2].pid) {
          UMA_HISTOGRAM_MEMORY_KB(L"Memory.Plugin", sample);
          is_plugin_process = true;
          break;
        }
      }
      if (!is_plugin_process) {
        if (trial.get()) {
          if (trial->boolean_value())
            UMA_HISTOGRAM_MEMORY_KB(L"Memory.Renderer_trial_high_memory",
                                    sample);
          else
            UMA_HISTOGRAM_MEMORY_KB(L"Memory.Renderer_trial_med_memory",
                                    sample);
        } else {
          UMA_HISTOGRAM_MEMORY_KB(L"Memory.Renderer", sample);
        }
      }
    }
  }
  UMA_HISTOGRAM_COUNTS_100(L"Memory.ProcessCount",
      static_cast<int>(browser.processes.size()));
  UMA_HISTOGRAM_COUNTS_100(L"Memory.PluginProcessCount",
      static_cast<int>(plugins_.size()));

  int total_sample = static_cast<int>(aggregate_memory / 1000);
  if (trial.get()) {
    if (trial->boolean_value())
      UMA_HISTOGRAM_MEMORY_MB(L"Memory.Total_trial_high_memory", total_sample);
    else
      UMA_HISTOGRAM_MEMORY_MB(L"Memory.Total_trial_med_memory", total_sample);
  } else {
    UMA_HISTOGRAM_MEMORY_MB(L"Memory.Total", total_sample);
  }
}

<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/plugin_updater.h"

#include <string>
#include <vector>

#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pepper_plugin_registry.h"
#include "chrome/common/pref_names.h"
#include "webkit/glue/plugins/webplugininfo.h"

// How long to wait to save the plugin enabled information, which might need to
// go to disk.
#define kPluginUpdateDelayMs (60 * 1000)

PluginUpdater::PluginUpdater()
    : enable_internal_pdf_(true),
      notify_pending_(false) {
}

DictionaryValue* PluginUpdater::CreatePluginFileSummary(
    const WebPluginInfo& plugin) {
  DictionaryValue* data = new DictionaryValue();
  data->SetString("path", plugin.path.value());
  data->SetString("name", plugin.name);
  data->SetString("version", plugin.version);
  data->SetBoolean("enabled", plugin.enabled);
  return data;
}

// static
ListValue* PluginUpdater::GetPluginGroupsData() {
  NPAPI::PluginList::PluginMap plugin_groups;
  NPAPI::PluginList::Singleton()->GetPluginGroups(true, &plugin_groups);

  // Construct DictionaryValues to return to the UI
  ListValue* plugin_groups_data = new ListValue();
  for (NPAPI::PluginList::PluginMap::const_iterator it =
       plugin_groups.begin();
       it != plugin_groups.end();
       ++it) {
    plugin_groups_data->Append(it->second->GetDataForUI());
  }
  return plugin_groups_data;
}

void PluginUpdater::EnablePluginGroup(bool enable, const string16& group_name) {
  if (PluginGroup::IsPluginNameDisabledByPolicy(group_name))
    enable = false;
  NPAPI::PluginList::Singleton()->EnableGroup(enable, group_name);
  NotifyPluginStatusChanged();
}

void PluginUpdater::EnablePluginFile(bool enable,
                                     const FilePath::StringType& path) {
  FilePath file_path(path);
  if (enable && !PluginGroup::IsPluginPathDisabledByPolicy(file_path))
    NPAPI::PluginList::Singleton()->EnablePlugin(file_path);
  else
    NPAPI::PluginList::Singleton()->DisablePlugin(file_path);

  NotifyPluginStatusChanged();
}

void PluginUpdater::Observe(NotificationType type,
                            const NotificationSource& source,
                            const NotificationDetails& details) {
  DCHECK_EQ(NotificationType::PREF_CHANGED, type.value);
  const std::string* pref_name = Details<std::string>(details).ptr();
  if (!pref_name) {
    NOTREACHED();
    return;
  }
  if (*pref_name == prefs::kPluginsPluginsBlacklist) {
    PrefService* pref_service = Source<PrefService>(source).ptr();
    const ListValue* list =
        pref_service->GetList(prefs::kPluginsPluginsBlacklist);
    DisablePluginsFromPolicy(list);
  }
}

void PluginUpdater::DisablePluginsFromPolicy(const ListValue* plugin_names) {
  // Generate the set of unique disabled plugin patterns from the disabled
  // plugins list.
  std::set<string16> policy_disabled_plugin_patterns;
  if (plugin_names) {
    ListValue::const_iterator end(plugin_names->end());
    for (ListValue::const_iterator current(plugin_names->begin());
         current != end; ++current) {
      string16 plugin_name;
      if ((*current)->GetAsString(&plugin_name)) {
        policy_disabled_plugin_patterns.insert(plugin_name);
      }
    }
  }
  PluginGroup::SetPolicyDisabledPluginPatterns(policy_disabled_plugin_patterns);

  NotifyPluginStatusChanged();
}

void PluginUpdater::DisablePluginGroupsFromPrefs(Profile* profile) {
  bool update_internal_dir = false;
  FilePath last_internal_dir =
  profile->GetPrefs()->GetFilePath(prefs::kPluginsLastInternalDirectory);
  FilePath cur_internal_dir;
  if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &cur_internal_dir) &&
      cur_internal_dir != last_internal_dir) {
    update_internal_dir = true;
    profile->GetPrefs()->SetFilePath(
        prefs::kPluginsLastInternalDirectory, cur_internal_dir);
  }

  if (!enable_internal_pdf_) {
    // This DCHECK guards against us disabling/enabling the pdf plugin more than
    // once without renaming the flag that tells us whether we can enable it
    // automatically.  Each time we disable the plugin by default after it was
    // enabled by default, we need to rename that flag.
    DCHECK(!profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF));
  }

  bool found_internal_pdf = false;
  bool force_enable_internal_pdf = false;
  string16 pdf_group_name = ASCIIToUTF16(PepperPluginRegistry::kPDFPluginName);
  FilePath pdf_path;
  PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path);
  FilePath::StringType pdf_path_str = pdf_path.value();
  if (enable_internal_pdf_ &&
      !profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF)) {
    // We switched to the internal pdf plugin being on by default, and so we
    // need to force it to be enabled.  We only want to do it this once though,
    // i.e. we don't want to enable it again if the user disables it afterwards.
    profile->GetPrefs()->SetBoolean(prefs::kPluginsEnabledInternalPDF, true);
    force_enable_internal_pdf = true;
  }

  if (ListValue* saved_plugins_list =
          profile->GetPrefs()->GetMutableList(prefs::kPluginsPluginsList)) {
    for (ListValue::const_iterator it = saved_plugins_list->begin();
         it != saved_plugins_list->end();
         ++it) {
      if (!(*it)->IsType(Value::TYPE_DICTIONARY)) {
        LOG(WARNING) << "Invalid entry in " << prefs::kPluginsPluginsList;
        continue;  // Oops, don't know what to do with this item.
      }

      DictionaryValue* plugin = static_cast<DictionaryValue*>(*it);
      string16 group_name;
      bool enabled = true;
      plugin->GetBoolean("enabled", &enabled);

      FilePath::StringType path;
      // The plugin list constains all the plugin files in addition to the
      // plugin groups.
      if (plugin->GetString("path", &path)) {
        // Files have a path attribute, groups don't.
        FilePath plugin_path(path);
        if (update_internal_dir &&
            FilePath::CompareIgnoreCase(plugin_path.DirName().value(),
                last_internal_dir.value()) == 0) {
          // If the internal plugin directory has changed and if the plugin
          // looks internal, update its path in the prefs.
          plugin_path = cur_internal_dir.Append(plugin_path.BaseName());
          path = plugin_path.value();
          plugin->SetString("path", path);
        }

        if (FilePath::CompareIgnoreCase(path, pdf_path_str) == 0) {
          found_internal_pdf = true;
          if (!enabled && force_enable_internal_pdf) {
            enabled = true;
            plugin->SetBoolean("enabled", true);
          }
        }
        if (!enabled)
          NPAPI::PluginList::Singleton()->DisablePlugin(plugin_path);
      } else if (!enabled && plugin->GetString("name", &group_name)) {
        // Don't disable this group if it's for the pdf plugin and we just
        // forced it on.
        if (force_enable_internal_pdf && pdf_group_name == group_name)
          continue;

        // Otherwise this is a list of groups.
        EnablePluginGroup(false, group_name);
      }
    }
  }

  // Build the set of policy-disabled plugin patterns once and cache it.
  // Don't do this in the constructor, there's no profile available there.
  const ListValue* plugin_blacklist =
      profile->GetPrefs()->GetList(prefs::kPluginsPluginsBlacklist);
  DisablePluginsFromPolicy(plugin_blacklist);

  if (!enable_internal_pdf_ && !found_internal_pdf) {
    // The internal PDF plugin is disabled by default, and the user hasn't
    // overridden the default.
    NPAPI::PluginList::Singleton()->DisablePlugin(pdf_path);
    EnablePluginGroup(false, pdf_group_name);
  }

  if (force_enable_internal_pdf) {
    // See http://crbug.com/50105 for background.
    EnablePluginGroup(false, ASCIIToUTF16(PluginGroup::kAdobeReader8GroupName));
    EnablePluginGroup(false, ASCIIToUTF16(PluginGroup::kAdobeReader9GroupName));

    // We want to save this, but doing so requires loading the list of plugins,
    // so do it after a minute as to not impact startup performance.  Note that
    // plugins are loaded after 30s by the metrics service.
    // TEMPORARY COMMENT OUT TO ELIMINATE FROM LINUX PERF BOT REGRESSIONS
    //UpdatePreferences(profile, kPluginUpdateDelayMs);
  }
}

void PluginUpdater::UpdatePreferences(Profile* profile, int delay_ms) {
  BrowserThread::PostDelayedTask(
    BrowserThread::FILE,
    FROM_HERE,
    NewRunnableFunction(
        &PluginUpdater::GetPreferencesDataOnFileThread, profile), delay_ms);
}

void PluginUpdater::GetPreferencesDataOnFileThread(void* profile) {
  std::vector<WebPluginInfo> plugins;
  NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);

  NPAPI::PluginList::PluginMap groups;
  NPAPI::PluginList::Singleton()->GetPluginGroups(false, &groups);

  BrowserThread::PostTask(
    BrowserThread::UI,
    FROM_HERE,
    NewRunnableFunction(
        &PluginUpdater::OnUpdatePreferences,
        static_cast<Profile*>(profile), plugins, groups));
}

void PluginUpdater::OnUpdatePreferences(
    Profile* profile,
    const std::vector<WebPluginInfo>& plugins,
    const NPAPI::PluginList::PluginMap& groups) {
  ListValue* plugins_list = profile->GetPrefs()->GetMutableList(
      prefs::kPluginsPluginsList);
  plugins_list->Clear();

  FilePath internal_dir;
  if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir))
    profile->GetPrefs()->SetFilePath(prefs::kPluginsLastInternalDirectory,
                                     internal_dir);

  // Add the plugin files.
  for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
       it != plugins.end();
       ++it) {
    plugins_list->Append(CreatePluginFileSummary(*it));
  }

  // Add the groups as well.
  for (NPAPI::PluginList::PluginMap::const_iterator it = groups.begin();
       it != groups.end(); ++it) {
    // Don't save preferences for vulnerable pugins.
    if (!CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableOutdatedPlugins) ||
        !it->second->IsVulnerable()) {
      plugins_list->Append(it->second->GetSummary());
    }
  }
}

void PluginUpdater::NotifyPluginStatusChanged() {
  if (notify_pending_)
    return;
  notify_pending_ = true;
  MessageLoop::current()->PostTask(
      FROM_HERE,
      NewRunnableFunction(&PluginUpdater::OnNotifyPluginStatusChanged));
}

void PluginUpdater::OnNotifyPluginStatusChanged() {
  GetPluginUpdater()->notify_pending_ = false;
  NotificationService::current()->Notify(
      NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
      Source<PluginUpdater>(GetPluginUpdater()),
      NotificationService::NoDetails());
}

/*static*/
PluginUpdater* PluginUpdater::GetPluginUpdater() {
  return Singleton<PluginUpdater>::get();
}
<commit_msg>Revert 64131: Try to track down Linux perf regressions.  TBR=sky<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/plugin_updater.h"

#include <string>
#include <vector>

#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pepper_plugin_registry.h"
#include "chrome/common/pref_names.h"
#include "webkit/glue/plugins/webplugininfo.h"

// How long to wait to save the plugin enabled information, which might need to
// go to disk.
#define kPluginUpdateDelayMs (60 * 1000)

PluginUpdater::PluginUpdater()
    : enable_internal_pdf_(true),
      notify_pending_(false) {
}

DictionaryValue* PluginUpdater::CreatePluginFileSummary(
    const WebPluginInfo& plugin) {
  DictionaryValue* data = new DictionaryValue();
  data->SetString("path", plugin.path.value());
  data->SetString("name", plugin.name);
  data->SetString("version", plugin.version);
  data->SetBoolean("enabled", plugin.enabled);
  return data;
}

// static
ListValue* PluginUpdater::GetPluginGroupsData() {
  NPAPI::PluginList::PluginMap plugin_groups;
  NPAPI::PluginList::Singleton()->GetPluginGroups(true, &plugin_groups);

  // Construct DictionaryValues to return to the UI
  ListValue* plugin_groups_data = new ListValue();
  for (NPAPI::PluginList::PluginMap::const_iterator it =
       plugin_groups.begin();
       it != plugin_groups.end();
       ++it) {
    plugin_groups_data->Append(it->second->GetDataForUI());
  }
  return plugin_groups_data;
}

void PluginUpdater::EnablePluginGroup(bool enable, const string16& group_name) {
  if (PluginGroup::IsPluginNameDisabledByPolicy(group_name))
    enable = false;
  NPAPI::PluginList::Singleton()->EnableGroup(enable, group_name);
  NotifyPluginStatusChanged();
}

void PluginUpdater::EnablePluginFile(bool enable,
                                     const FilePath::StringType& path) {
  FilePath file_path(path);
  if (enable && !PluginGroup::IsPluginPathDisabledByPolicy(file_path))
    NPAPI::PluginList::Singleton()->EnablePlugin(file_path);
  else
    NPAPI::PluginList::Singleton()->DisablePlugin(file_path);

  NotifyPluginStatusChanged();
}

void PluginUpdater::Observe(NotificationType type,
                            const NotificationSource& source,
                            const NotificationDetails& details) {
  DCHECK_EQ(NotificationType::PREF_CHANGED, type.value);
  const std::string* pref_name = Details<std::string>(details).ptr();
  if (!pref_name) {
    NOTREACHED();
    return;
  }
  if (*pref_name == prefs::kPluginsPluginsBlacklist) {
    PrefService* pref_service = Source<PrefService>(source).ptr();
    const ListValue* list =
        pref_service->GetList(prefs::kPluginsPluginsBlacklist);
    DisablePluginsFromPolicy(list);
  }
}

void PluginUpdater::DisablePluginsFromPolicy(const ListValue* plugin_names) {
  // Generate the set of unique disabled plugin patterns from the disabled
  // plugins list.
  std::set<string16> policy_disabled_plugin_patterns;
  if (plugin_names) {
    ListValue::const_iterator end(plugin_names->end());
    for (ListValue::const_iterator current(plugin_names->begin());
         current != end; ++current) {
      string16 plugin_name;
      if ((*current)->GetAsString(&plugin_name)) {
        policy_disabled_plugin_patterns.insert(plugin_name);
      }
    }
  }
  PluginGroup::SetPolicyDisabledPluginPatterns(policy_disabled_plugin_patterns);

  NotifyPluginStatusChanged();
}

void PluginUpdater::DisablePluginGroupsFromPrefs(Profile* profile) {
  bool update_internal_dir = false;
  FilePath last_internal_dir =
  profile->GetPrefs()->GetFilePath(prefs::kPluginsLastInternalDirectory);
  FilePath cur_internal_dir;
  if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &cur_internal_dir) &&
      cur_internal_dir != last_internal_dir) {
    update_internal_dir = true;
    profile->GetPrefs()->SetFilePath(
        prefs::kPluginsLastInternalDirectory, cur_internal_dir);
  }

  if (!enable_internal_pdf_) {
    // This DCHECK guards against us disabling/enabling the pdf plugin more than
    // once without renaming the flag that tells us whether we can enable it
    // automatically.  Each time we disable the plugin by default after it was
    // enabled by default, we need to rename that flag.
    DCHECK(!profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF));
  }

  bool found_internal_pdf = false;
  bool force_enable_internal_pdf = false;
  string16 pdf_group_name = ASCIIToUTF16(PepperPluginRegistry::kPDFPluginName);
  FilePath pdf_path;
  PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path);
  FilePath::StringType pdf_path_str = pdf_path.value();
  if (enable_internal_pdf_ &&
      !profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF)) {
    // We switched to the internal pdf plugin being on by default, and so we
    // need to force it to be enabled.  We only want to do it this once though,
    // i.e. we don't want to enable it again if the user disables it afterwards.
    profile->GetPrefs()->SetBoolean(prefs::kPluginsEnabledInternalPDF, true);
    force_enable_internal_pdf = true;
  }

  if (ListValue* saved_plugins_list =
          profile->GetPrefs()->GetMutableList(prefs::kPluginsPluginsList)) {
    for (ListValue::const_iterator it = saved_plugins_list->begin();
         it != saved_plugins_list->end();
         ++it) {
      if (!(*it)->IsType(Value::TYPE_DICTIONARY)) {
        LOG(WARNING) << "Invalid entry in " << prefs::kPluginsPluginsList;
        continue;  // Oops, don't know what to do with this item.
      }

      DictionaryValue* plugin = static_cast<DictionaryValue*>(*it);
      string16 group_name;
      bool enabled = true;
      plugin->GetBoolean("enabled", &enabled);

      FilePath::StringType path;
      // The plugin list constains all the plugin files in addition to the
      // plugin groups.
      if (plugin->GetString("path", &path)) {
        // Files have a path attribute, groups don't.
        FilePath plugin_path(path);
        if (update_internal_dir &&
            FilePath::CompareIgnoreCase(plugin_path.DirName().value(),
                last_internal_dir.value()) == 0) {
          // If the internal plugin directory has changed and if the plugin
          // looks internal, update its path in the prefs.
          plugin_path = cur_internal_dir.Append(plugin_path.BaseName());
          path = plugin_path.value();
          plugin->SetString("path", path);
        }

        if (FilePath::CompareIgnoreCase(path, pdf_path_str) == 0) {
          found_internal_pdf = true;
          if (!enabled && force_enable_internal_pdf) {
            enabled = true;
            plugin->SetBoolean("enabled", true);
          }
        }
        if (!enabled)
          NPAPI::PluginList::Singleton()->DisablePlugin(plugin_path);
      } else if (!enabled && plugin->GetString("name", &group_name)) {
        // Don't disable this group if it's for the pdf plugin and we just
        // forced it on.
        if (force_enable_internal_pdf && pdf_group_name == group_name)
          continue;

        // Otherwise this is a list of groups.
        EnablePluginGroup(false, group_name);
      }
    }
  }

  // Build the set of policy-disabled plugin patterns once and cache it.
  // Don't do this in the constructor, there's no profile available there.
  const ListValue* plugin_blacklist =
      profile->GetPrefs()->GetList(prefs::kPluginsPluginsBlacklist);
  DisablePluginsFromPolicy(plugin_blacklist);

  if (!enable_internal_pdf_ && !found_internal_pdf) {
    // The internal PDF plugin is disabled by default, and the user hasn't
    // overridden the default.
    NPAPI::PluginList::Singleton()->DisablePlugin(pdf_path);
    EnablePluginGroup(false, pdf_group_name);
  }

  if (force_enable_internal_pdf) {
    // See http://crbug.com/50105 for background.
    EnablePluginGroup(false, ASCIIToUTF16(PluginGroup::kAdobeReader8GroupName));
    EnablePluginGroup(false, ASCIIToUTF16(PluginGroup::kAdobeReader9GroupName));

    // We want to save this, but doing so requires loading the list of plugins,
    // so do it after a minute as to not impact startup performance.  Note that
    // plugins are loaded after 30s by the metrics service.
    UpdatePreferences(profile, kPluginUpdateDelayMs);
  }
}

void PluginUpdater::UpdatePreferences(Profile* profile, int delay_ms) {
  BrowserThread::PostDelayedTask(
    BrowserThread::FILE,
    FROM_HERE,
    NewRunnableFunction(
        &PluginUpdater::GetPreferencesDataOnFileThread, profile), delay_ms);
}

void PluginUpdater::GetPreferencesDataOnFileThread(void* profile) {
  std::vector<WebPluginInfo> plugins;
  NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);

  NPAPI::PluginList::PluginMap groups;
  NPAPI::PluginList::Singleton()->GetPluginGroups(false, &groups);

  BrowserThread::PostTask(
    BrowserThread::UI,
    FROM_HERE,
    NewRunnableFunction(
        &PluginUpdater::OnUpdatePreferences,
        static_cast<Profile*>(profile), plugins, groups));
}

void PluginUpdater::OnUpdatePreferences(
    Profile* profile,
    const std::vector<WebPluginInfo>& plugins,
    const NPAPI::PluginList::PluginMap& groups) {
  ListValue* plugins_list = profile->GetPrefs()->GetMutableList(
      prefs::kPluginsPluginsList);
  plugins_list->Clear();

  FilePath internal_dir;
  if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir))
    profile->GetPrefs()->SetFilePath(prefs::kPluginsLastInternalDirectory,
                                     internal_dir);

  // Add the plugin files.
  for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
       it != plugins.end();
       ++it) {
    plugins_list->Append(CreatePluginFileSummary(*it));
  }

  // Add the groups as well.
  for (NPAPI::PluginList::PluginMap::const_iterator it = groups.begin();
       it != groups.end(); ++it) {
    // Don't save preferences for vulnerable pugins.
    if (!CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableOutdatedPlugins) ||
        !it->second->IsVulnerable()) {
      plugins_list->Append(it->second->GetSummary());
    }
  }
}

void PluginUpdater::NotifyPluginStatusChanged() {
  if (notify_pending_)
    return;
  notify_pending_ = true;
  MessageLoop::current()->PostTask(
      FROM_HERE,
      NewRunnableFunction(&PluginUpdater::OnNotifyPluginStatusChanged));
}

void PluginUpdater::OnNotifyPluginStatusChanged() {
  GetPluginUpdater()->notify_pending_ = false;
  NotificationService::current()->Notify(
      NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
      Source<PluginUpdater>(GetPluginUpdater()),
      NotificationService::NoDetails());
}

/*static*/
PluginUpdater* PluginUpdater::GetPluginUpdater() {
  return Singleton<PluginUpdater>::get();
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/json_pref_store.h"

#include <algorithm>

#include "base/bind.h"
#include "base/callback.h"
#include "base/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop_proxy.h"
#include "base/values.h"
#include "content/common/json_value_serializer.h"

namespace {

// Some extensions we'll tack on to copies of the Preferences files.
const FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad");

// Differentiates file loading between origin thread and passed
// (aka file) thread.
class FileThreadDeserializer
    : public base::RefCountedThreadSafe<FileThreadDeserializer> {
 public:
  explicit FileThreadDeserializer(JsonPrefStore* delegate,
                                  base::MessageLoopProxy* file_loop_proxy)
      : delegate_(delegate),
        file_loop_proxy_(file_loop_proxy),
        origin_loop_proxy_(base::MessageLoopProxy::CreateForCurrentThread()) {
  }

  void Start(const FilePath& path) {
    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
    file_loop_proxy_->PostTask(
        FROM_HERE,
        NewRunnableMethod(this,
                          &FileThreadDeserializer::ReadFileAndReport,
                          path));
  }

  // Deserializes JSON on the file thread.
  void ReadFileAndReport(const FilePath& path) {
    DCHECK(file_loop_proxy_->BelongsToCurrentThread());

    value_.reset(DoReading(path, &error_, &no_dir_));

    origin_loop_proxy_->PostTask(
        FROM_HERE,
        NewRunnableMethod(this, &FileThreadDeserializer::ReportOnOriginThread));
  }

  // Reports deserialization result on the origin thread.
  void ReportOnOriginThread() {
    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
    delegate_->OnFileRead(value_.release(), error_, no_dir_);
  }

  static Value* DoReading(const FilePath& path,
                          PersistentPrefStore::PrefReadError* error,
                          bool* no_dir) {
    int error_code;
    std::string error_msg;
    JSONFileValueSerializer serializer(path);
    Value* value = serializer.Deserialize(&error_code, &error_msg);
    HandleErrors(value, path, error_code, error_msg, error);
    *no_dir = !file_util::PathExists(path.DirName());
    return value;
  }

  static void HandleErrors(const Value* value,
                           const FilePath& path,
                           int error_code,
                           const std::string& error_msg,
                           PersistentPrefStore::PrefReadError* error);

 private:
  friend class base::RefCountedThreadSafe<FileThreadDeserializer>;

  bool no_dir_;
  PersistentPrefStore::PrefReadError error_;
  scoped_ptr<Value> value_;
  scoped_refptr<JsonPrefStore> delegate_;
  scoped_refptr<base::MessageLoopProxy> file_loop_proxy_;
  scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;
};

// static
void FileThreadDeserializer::HandleErrors(
    const Value* value,
    const FilePath& path,
    int error_code,
    const std::string& error_msg,
    PersistentPrefStore::PrefReadError* error) {
  *error = PersistentPrefStore::PREF_READ_ERROR_NONE;
  if (!value) {
    VLOG(1) << "Error while loading JSON file: " << error_msg;
    switch (error_code) {
      case JSONFileValueSerializer::JSON_ACCESS_DENIED:
        *error = PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
        break;
      case JSONFileValueSerializer::JSON_CANNOT_READ_FILE:
        *error = PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
        break;
      case JSONFileValueSerializer::JSON_FILE_LOCKED:
        *error = PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
        break;
      case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
        *error = PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
        break;
      default:
        *error = PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
        // JSON errors indicate file corruption of some sort.
        // Since the file is corrupt, move it to the side and continue with
        // empty preferences.  This will result in them losing their settings.
        // We keep the old file for possible support and debugging assistance
        // as well as to detect if they're seeing these errors repeatedly.
        // TODO(erikkay) Instead, use the last known good file.
        FilePath bad = path.ReplaceExtension(kBadExtension);

        // If they've ever had a parse error before, put them in another bucket.
        // TODO(erikkay) if we keep this error checking for very long, we may
        // want to differentiate between recent and long ago errors.
        if (file_util::PathExists(bad))
          *error = PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT;
        file_util::Move(path, bad);
        break;
    }
  } else if (!value->IsType(Value::TYPE_DICTIONARY)) {
    *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
  }
}

}  // namespace

JsonPrefStore::JsonPrefStore(const FilePath& filename,
                             base::MessageLoopProxy* file_message_loop_proxy)
    : path_(filename),
      file_message_loop_proxy_(file_message_loop_proxy),
      prefs_(new DictionaryValue()),
      read_only_(false),
      writer_(filename, file_message_loop_proxy),
      error_delegate_(NULL),
      initialized_(false) {
}

JsonPrefStore::~JsonPrefStore() {
  CommitPendingWrite();
}

PrefStore::ReadResult JsonPrefStore::GetValue(const std::string& key,
                                              const Value** result) const {
  Value* tmp = NULL;
  if (prefs_->Get(key, &tmp)) {
    *result = tmp;
    return READ_OK;
  }
  return READ_NO_VALUE;
}

void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
  observers_.AddObserver(observer);
}

void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
  observers_.RemoveObserver(observer);
}

bool JsonPrefStore::IsInitializationComplete() const {
  return initialized_;
}

PrefStore::ReadResult JsonPrefStore::GetMutableValue(const std::string& key,
                                                     Value** result) {
  return prefs_->Get(key, result) ? READ_OK : READ_NO_VALUE;
}

void JsonPrefStore::SetValue(const std::string& key, Value* value) {
  DCHECK(value);
  scoped_ptr<Value> new_value(value);
  Value* old_value = NULL;
  prefs_->Get(key, &old_value);
  if (!old_value || !value->Equals(old_value)) {
    prefs_->Set(key, new_value.release());
    FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
  }
}

void JsonPrefStore::SetValueSilently(const std::string& key, Value* value) {
  DCHECK(value);
  scoped_ptr<Value> new_value(value);
  Value* old_value = NULL;
  prefs_->Get(key, &old_value);
  if (!old_value || !value->Equals(old_value))
    prefs_->Set(key, new_value.release());
}

void JsonPrefStore::RemoveValue(const std::string& key) {
  if (prefs_->Remove(key, NULL)) {
    FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
  }
}

bool JsonPrefStore::ReadOnly() const {
  return read_only_;
}

void JsonPrefStore::OnFileRead(Value* value_owned,
                               PersistentPrefStore::PrefReadError error,
                               bool no_dir) {
  scoped_ptr<Value> value(value_owned);
  initialized_ = true;

  if (no_dir) {
    FOR_EACH_OBSERVER(PrefStore::Observer,
                      observers_,
                      OnInitializationCompleted(false));
    return;
  }

  switch (error) {
    case PREF_READ_ERROR_ACCESS_DENIED:
    case PREF_READ_ERROR_FILE_OTHER:
    case PREF_READ_ERROR_FILE_LOCKED:
    case PREF_READ_ERROR_JSON_TYPE:
    case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
      read_only_ = true;
      break;
    case PREF_READ_ERROR_NONE:
      DCHECK(value.get());
      prefs_.reset(static_cast<DictionaryValue*>(value.release()));
      break;
    case PREF_READ_ERROR_NO_FILE:
      // If the file just doesn't exist, maybe this is first run.  In any case
      // there's no harm in writing out default prefs in this case.
      break;
    case PREF_READ_ERROR_JSON_PARSE:
    case PREF_READ_ERROR_JSON_REPEAT:
      break;
    default:
      NOTREACHED() << "Unknown error: " << error;
  }

  if (error_delegate_.get() && error != PREF_READ_ERROR_NONE)
    error_delegate_->OnError(error);

  FOR_EACH_OBSERVER(PrefStore::Observer,
                    observers_,
                    OnInitializationCompleted(true));
}

void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) {
  initialized_ = false;
  error_delegate_.reset(error_delegate);
  if (path_.empty()) {
    OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
    return;
  }

  // Start async reading of the preferences file. It will delete itself
  // in the end.
  scoped_refptr<FileThreadDeserializer> deserializer(
      new FileThreadDeserializer(this, file_message_loop_proxy_.get()));
  deserializer->Start(path_);
}

PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
  if (path_.empty()) {
    OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
    return PREF_READ_ERROR_FILE_NOT_SPECIFIED;
  }

  PrefReadError error;
  bool no_dir;
  Value* value = FileThreadDeserializer::DoReading(path_, &error, &no_dir);
  OnFileRead(value, error, no_dir);
  return error;
}

bool JsonPrefStore::WritePrefs() {
  std::string data;
  if (!SerializeData(&data))
    return false;

  // Lie about our ability to save.
  if (read_only_)
    return true;

  writer_.WriteNow(data);
  return true;
}

void JsonPrefStore::ScheduleWritePrefs() {
  if (read_only_)
    return;

  writer_.ScheduleWrite(this);
}

void JsonPrefStore::CommitPendingWrite() {
  if (writer_.HasPendingWrite() && !read_only_)
    writer_.DoScheduledWrite();
}

void JsonPrefStore::ReportValueChanged(const std::string& key) {
  FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
}

bool JsonPrefStore::SerializeData(std::string* output) {
  // TODO(tc): Do we want to prune webkit preferences that match the default
  // value?
  JSONStringValueSerializer serializer(output);
  serializer.set_pretty_print(true);
  scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren());
  return serializer.Serialize(*(copy.get()));
}
<commit_msg>Uninitialized members in FileThreadDeserializer.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/json_pref_store.h"

#include <algorithm>

#include "base/bind.h"
#include "base/callback.h"
#include "base/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop_proxy.h"
#include "base/values.h"
#include "content/common/json_value_serializer.h"

namespace {

// Some extensions we'll tack on to copies of the Preferences files.
const FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad");

// Differentiates file loading between origin thread and passed
// (aka file) thread.
class FileThreadDeserializer
    : public base::RefCountedThreadSafe<FileThreadDeserializer> {
 public:
  explicit FileThreadDeserializer(JsonPrefStore* delegate,
                                  base::MessageLoopProxy* file_loop_proxy)
      : no_dir_(false),
        error_(PersistentPrefStore::PREF_READ_ERROR_NONE),
        delegate_(delegate),
        file_loop_proxy_(file_loop_proxy),
        origin_loop_proxy_(base::MessageLoopProxy::CreateForCurrentThread()) {
  }

  void Start(const FilePath& path) {
    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
    file_loop_proxy_->PostTask(
        FROM_HERE,
        NewRunnableMethod(this,
                          &FileThreadDeserializer::ReadFileAndReport,
                          path));
  }

  // Deserializes JSON on the file thread.
  void ReadFileAndReport(const FilePath& path) {
    DCHECK(file_loop_proxy_->BelongsToCurrentThread());

    value_.reset(DoReading(path, &error_, &no_dir_));

    origin_loop_proxy_->PostTask(
        FROM_HERE,
        NewRunnableMethod(this, &FileThreadDeserializer::ReportOnOriginThread));
  }

  // Reports deserialization result on the origin thread.
  void ReportOnOriginThread() {
    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
    delegate_->OnFileRead(value_.release(), error_, no_dir_);
  }

  static Value* DoReading(const FilePath& path,
                          PersistentPrefStore::PrefReadError* error,
                          bool* no_dir) {
    int error_code;
    std::string error_msg;
    JSONFileValueSerializer serializer(path);
    Value* value = serializer.Deserialize(&error_code, &error_msg);
    HandleErrors(value, path, error_code, error_msg, error);
    *no_dir = !file_util::PathExists(path.DirName());
    return value;
  }

  static void HandleErrors(const Value* value,
                           const FilePath& path,
                           int error_code,
                           const std::string& error_msg,
                           PersistentPrefStore::PrefReadError* error);

 private:
  friend class base::RefCountedThreadSafe<FileThreadDeserializer>;

  bool no_dir_;
  PersistentPrefStore::PrefReadError error_;
  scoped_ptr<Value> value_;
  scoped_refptr<JsonPrefStore> delegate_;
  scoped_refptr<base::MessageLoopProxy> file_loop_proxy_;
  scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;
};

// static
void FileThreadDeserializer::HandleErrors(
    const Value* value,
    const FilePath& path,
    int error_code,
    const std::string& error_msg,
    PersistentPrefStore::PrefReadError* error) {
  *error = PersistentPrefStore::PREF_READ_ERROR_NONE;
  if (!value) {
    VLOG(1) << "Error while loading JSON file: " << error_msg;
    switch (error_code) {
      case JSONFileValueSerializer::JSON_ACCESS_DENIED:
        *error = PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
        break;
      case JSONFileValueSerializer::JSON_CANNOT_READ_FILE:
        *error = PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
        break;
      case JSONFileValueSerializer::JSON_FILE_LOCKED:
        *error = PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
        break;
      case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
        *error = PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
        break;
      default:
        *error = PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
        // JSON errors indicate file corruption of some sort.
        // Since the file is corrupt, move it to the side and continue with
        // empty preferences.  This will result in them losing their settings.
        // We keep the old file for possible support and debugging assistance
        // as well as to detect if they're seeing these errors repeatedly.
        // TODO(erikkay) Instead, use the last known good file.
        FilePath bad = path.ReplaceExtension(kBadExtension);

        // If they've ever had a parse error before, put them in another bucket.
        // TODO(erikkay) if we keep this error checking for very long, we may
        // want to differentiate between recent and long ago errors.
        if (file_util::PathExists(bad))
          *error = PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT;
        file_util::Move(path, bad);
        break;
    }
  } else if (!value->IsType(Value::TYPE_DICTIONARY)) {
    *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
  }
}

}  // namespace

JsonPrefStore::JsonPrefStore(const FilePath& filename,
                             base::MessageLoopProxy* file_message_loop_proxy)
    : path_(filename),
      file_message_loop_proxy_(file_message_loop_proxy),
      prefs_(new DictionaryValue()),
      read_only_(false),
      writer_(filename, file_message_loop_proxy),
      error_delegate_(NULL),
      initialized_(false) {
}

JsonPrefStore::~JsonPrefStore() {
  CommitPendingWrite();
}

PrefStore::ReadResult JsonPrefStore::GetValue(const std::string& key,
                                              const Value** result) const {
  Value* tmp = NULL;
  if (prefs_->Get(key, &tmp)) {
    *result = tmp;
    return READ_OK;
  }
  return READ_NO_VALUE;
}

void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
  observers_.AddObserver(observer);
}

void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
  observers_.RemoveObserver(observer);
}

bool JsonPrefStore::IsInitializationComplete() const {
  return initialized_;
}

PrefStore::ReadResult JsonPrefStore::GetMutableValue(const std::string& key,
                                                     Value** result) {
  return prefs_->Get(key, result) ? READ_OK : READ_NO_VALUE;
}

void JsonPrefStore::SetValue(const std::string& key, Value* value) {
  DCHECK(value);
  scoped_ptr<Value> new_value(value);
  Value* old_value = NULL;
  prefs_->Get(key, &old_value);
  if (!old_value || !value->Equals(old_value)) {
    prefs_->Set(key, new_value.release());
    FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
  }
}

void JsonPrefStore::SetValueSilently(const std::string& key, Value* value) {
  DCHECK(value);
  scoped_ptr<Value> new_value(value);
  Value* old_value = NULL;
  prefs_->Get(key, &old_value);
  if (!old_value || !value->Equals(old_value))
    prefs_->Set(key, new_value.release());
}

void JsonPrefStore::RemoveValue(const std::string& key) {
  if (prefs_->Remove(key, NULL)) {
    FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
  }
}

bool JsonPrefStore::ReadOnly() const {
  return read_only_;
}

void JsonPrefStore::OnFileRead(Value* value_owned,
                               PersistentPrefStore::PrefReadError error,
                               bool no_dir) {
  scoped_ptr<Value> value(value_owned);
  initialized_ = true;

  if (no_dir) {
    FOR_EACH_OBSERVER(PrefStore::Observer,
                      observers_,
                      OnInitializationCompleted(false));
    return;
  }

  switch (error) {
    case PREF_READ_ERROR_ACCESS_DENIED:
    case PREF_READ_ERROR_FILE_OTHER:
    case PREF_READ_ERROR_FILE_LOCKED:
    case PREF_READ_ERROR_JSON_TYPE:
    case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
      read_only_ = true;
      break;
    case PREF_READ_ERROR_NONE:
      DCHECK(value.get());
      prefs_.reset(static_cast<DictionaryValue*>(value.release()));
      break;
    case PREF_READ_ERROR_NO_FILE:
      // If the file just doesn't exist, maybe this is first run.  In any case
      // there's no harm in writing out default prefs in this case.
      break;
    case PREF_READ_ERROR_JSON_PARSE:
    case PREF_READ_ERROR_JSON_REPEAT:
      break;
    default:
      NOTREACHED() << "Unknown error: " << error;
  }

  if (error_delegate_.get() && error != PREF_READ_ERROR_NONE)
    error_delegate_->OnError(error);

  FOR_EACH_OBSERVER(PrefStore::Observer,
                    observers_,
                    OnInitializationCompleted(true));
}

void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) {
  initialized_ = false;
  error_delegate_.reset(error_delegate);
  if (path_.empty()) {
    OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
    return;
  }

  // Start async reading of the preferences file. It will delete itself
  // in the end.
  scoped_refptr<FileThreadDeserializer> deserializer(
      new FileThreadDeserializer(this, file_message_loop_proxy_.get()));
  deserializer->Start(path_);
}

PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
  if (path_.empty()) {
    OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
    return PREF_READ_ERROR_FILE_NOT_SPECIFIED;
  }

  PrefReadError error;
  bool no_dir;
  Value* value = FileThreadDeserializer::DoReading(path_, &error, &no_dir);
  OnFileRead(value, error, no_dir);
  return error;
}

bool JsonPrefStore::WritePrefs() {
  std::string data;
  if (!SerializeData(&data))
    return false;

  // Lie about our ability to save.
  if (read_only_)
    return true;

  writer_.WriteNow(data);
  return true;
}

void JsonPrefStore::ScheduleWritePrefs() {
  if (read_only_)
    return;

  writer_.ScheduleWrite(this);
}

void JsonPrefStore::CommitPendingWrite() {
  if (writer_.HasPendingWrite() && !read_only_)
    writer_.DoScheduledWrite();
}

void JsonPrefStore::ReportValueChanged(const std::string& key) {
  FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
}

bool JsonPrefStore::SerializeData(std::string* output) {
  // TODO(tc): Do we want to prune webkit preferences that match the default
  // value?
  JSONStringValueSerializer serializer(output);
  serializer.set_pretty_print(true);
  scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren());
  return serializer.Serialize(*(copy.get()));
}
<|endoftext|>


<commit_before><commit_msg>Disable multiple paint rects due to page cycler regression on single-core-xp.<commit_after><|endoftext|>


<commit_before>#include <atomic>
#include <cstdlib>
#include <memory>
#include <thread>
#include <vector>

#include <iostream>

#include "libs/catch/catch.hpp"
#include "libs/exceptionpp/exception.h"

#include "src/simpleconcurrentcache.h"
#include "src/simpleserialcache.h"
#include "src/simpleline.h"

void concurrentcache_multithread_worker(std::shared_ptr<std::atomic<size_t>> result, std::shared_ptr<cachepp::SimpleConcurrentCache<cachepp::SimpleLine>> c, std::shared_ptr<std::vector<std::shared_ptr<cachepp::SimpleLine>>> v) {
	size_t n_attempts = 1000;
	size_t n_success = 0;
	for(size_t attempt = 0; attempt < n_attempts; ++attempt) {
		cachepp::identifier index = rand() % v->size();
		c->acquire(v->at(index));
		n_success += v->at(index)->get_is_loaded();
		c->release(v->at(index));
	}

	*result += (n_success == n_attempts);
}

TEST_CASE("cachepp|serialcache") {
	std::shared_ptr<cachepp::SimpleSerialCache<cachepp::SimpleLine>> c (new cachepp::SimpleSerialCache<cachepp::SimpleLine>(1));

	std::vector<std::shared_ptr<cachepp::SimpleLine>> v (0);
	for(size_t i = 0; i < 10; ++i) {
		v.push_back(std::shared_ptr<cachepp::SimpleLine> (new cachepp::SimpleLine(i, false)));
	}

	for(size_t i = 0; i < v.size(); ++i) {
		REQUIRE(v.at(i)->get_is_loaded() == false);
	}

	/**
	 * test cache line juggling
	 */

	for(size_t i = 0; i < v.size(); ++i) {
		c->acquire(v.at(i));
		REQUIRE(v.at(i)->get_is_loaded() == true);
	}

	size_t loaded_lines = 0;
	for(size_t i = 0; i < v.size(); ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 2);

	c->clear();

	loaded_lines = 0;
	for(size_t i = 0; i < v.size(); ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 0);

	/**
	 * test selection policy
	 */

	c->acquire(v.at(0));
	c->acquire(v.at(1));

	c->acquire(v.at(0));
	c->acquire(v.at(2));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(1)->get_is_loaded() == false);
	REQUIRE(v.at(2)->get_is_loaded() == true);

	c->acquire(v.at(3));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(3)->get_is_loaded() == true);

	std::cout << "cachepp|serialcache: " << c->get_miss_rate() << std::endl;
}

TEST_CASE("cachepp|concurrentcache-singlethread") {
	std::shared_ptr<cachepp::SimpleConcurrentCache<cachepp::SimpleLine>> c (new cachepp::SimpleConcurrentCache<cachepp::SimpleLine>(1));

	std::vector<std::shared_ptr<cachepp::SimpleLine>> v (0);
	for(size_t i = 0; i < 10; ++i) {
		v.push_back(std::shared_ptr<cachepp::SimpleLine> (new cachepp::SimpleLine(i, false)));
	}

	for(size_t i = 0; i < v.size(); ++i) {
		REQUIRE(v.at(i)->get_is_loaded() == false);
	}

	/**
	 * test cache line juggling
	 */

	for(size_t i = 0; i < v.size(); ++i) {
		c->acquire(v.at(i));
		REQUIRE(v.at(i)->get_is_loaded() == true);
	}

	size_t loaded_lines = 0;
	for(size_t i = 0; i < v.size(); ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 2);

	c->clear();

	loaded_lines = 0;
	for(size_t i = 0; i < v.size(); ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 0);

	/**
	 * test selection policy
	 */

	c->acquire(v.at(0));
	c->acquire(v.at(1));

	c->acquire(v.at(0));
	c->acquire(v.at(2));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(1)->get_is_loaded() == false);
	REQUIRE(v.at(2)->get_is_loaded() == true);

	c->acquire(v.at(3));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(3)->get_is_loaded() == true);

	std::cout << "cachepp|concurrentcache-singlethread: " << c->get_miss_rate() << std::endl;
}
/**
TEST_CASE("cachepp|concurrentcache-multithread") {
	size_t n_threads = 16;
	size_t n_attempts = 1000;

	std::shared_ptr<cachepp::SimpleConcurrentCache<cachepp::SimpleLine>> c (new cachepp::SimpleConcurrentCache<cachepp::SimpleLine>(2));
	std::shared_ptr<std::vector<std::shared_ptr<cachepp::SimpleLine>>> v (new std::vector<std::shared_ptr<cachepp::SimpleLine>> (0));

	for(size_t i = 0; i < 10; ++i) {
		v->push_back(std::shared_ptr<cachepp::SimpleLine> (new cachepp::SimpleLine(i, false)));
	}

	std::vector<std::thread> threads;

	std::shared_ptr<std::atomic<size_t>> result (new std::atomic<size_t>());
	for(size_t attempt = 0; attempt < n_attempts; ++attempt) {
		for(size_t i = 0; i < n_threads; ++i) {
			threads.push_back(std::thread(concurrentcache_multithread_worker, result, c, v));
		}

		for(size_t i = 0; i < n_threads; ++i) {
			threads.at(i).join();
		}
	}

	REQUIRE(*result == (n_attempts * n_threads));
}
*/
<commit_msg>bug fixes<commit_after>#include <atomic>
#include <cstdlib>
#include <memory>
#include <thread>
#include <vector>

#include <iostream>

#include "libs/catch/catch.hpp"
#include "libs/exceptionpp/exception.h"

#include "src/simpleconcurrentcache.h"
#include "src/simpleserialcache.h"
#include "src/simpleline.h"

void concurrentcache_multithread_worker(std::shared_ptr<std::atomic<size_t>> result, std::shared_ptr<cachepp::SimpleConcurrentCache<cachepp::SimpleLine>> c, std::shared_ptr<std::vector<std::shared_ptr<cachepp::SimpleLine>>> v) {
	size_t n_attempts = 1000;
	size_t n_success = 0;
	for(size_t attempt = 0; attempt < n_attempts; ++attempt) {
		cachepp::identifier index = rand() % v->size();
		c->acquire(v->at(index));
		n_success += v->at(index)->get_is_loaded();
		c->release(v->at(index));
	}

	*result += (n_success == n_attempts);
}

TEST_CASE("cachepp|serialcache") {
	std::shared_ptr<cachepp::SimpleSerialCache<cachepp::SimpleLine>> c (new cachepp::SimpleSerialCache<cachepp::SimpleLine>(2));

	std::vector<std::shared_ptr<cachepp::SimpleLine>> v (0);
	for(size_t i = 0; i < 10; ++i) {
		v.push_back(std::shared_ptr<cachepp::SimpleLine> (new cachepp::SimpleLine(i, false)));
	}

	for(size_t i = 0; i < v.size(); ++i) {
		REQUIRE(v.at(i)->get_is_loaded() == false);
	}

	/**
	 * test cache line juggling
	 */

	for(size_t i = 0; i < v.size(); ++i) {
		c->acquire(v.at(i));
		REQUIRE(v.at(i)->get_is_loaded() == true);
	}

	size_t loaded_lines = 0;
	for(size_t i = 0; i < v.size(); ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 2);

	c->clear();

	loaded_lines = 0;
	for(size_t i = 0; i < v.size(); ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 0);

	/**
	 * test selection policy
	 */

	c->acquire(v.at(0));
	c->acquire(v.at(1));

	c->acquire(v.at(0));
	c->acquire(v.at(2));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(1)->get_is_loaded() == false);
	REQUIRE(v.at(2)->get_is_loaded() == true);

	c->acquire(v.at(3));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(3)->get_is_loaded() == true);

	std::cout << "cachepp|serialcache: " << c->get_miss_rate() << std::endl;
}

TEST_CASE("cachepp|concurrentcache-singlethread") {
	std::shared_ptr<cachepp::SimpleConcurrentCache<cachepp::SimpleLine>> c (new cachepp::SimpleConcurrentCache<cachepp::SimpleLine>(2));

	std::vector<std::shared_ptr<cachepp::SimpleLine>> v (0);
	for(size_t i = 0; i < 10; ++i) {
		v.push_back(std::shared_ptr<cachepp::SimpleLine> (new cachepp::SimpleLine(i, false)));
	}

	for(size_t i = 0; i < v.size(); ++i) {
		REQUIRE(v.at(i)->get_is_loaded() == false);
	}

	/**
	 * test cache line juggling
	 */

	for(size_t i = 0; i < v.size(); ++i) {
		c->acquire(v.at(i));
		REQUIRE(v.at(i)->get_is_loaded() == true);
	}

	size_t loaded_lines = 0;
	for(size_t i = 0; i < v.size(); ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 2);

	c->clear();

	loaded_lines = 0;
	for(size_t i = 0; i < v.size(); ++i) {
		loaded_lines += v.at(i)->get_is_loaded();
	}

	REQUIRE(loaded_lines == 0);

	/**
	 * test selection policy
	 */

	c->acquire(v.at(0));
	c->acquire(v.at(1));

	c->acquire(v.at(0));
	c->acquire(v.at(2));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(1)->get_is_loaded() == false);
	REQUIRE(v.at(2)->get_is_loaded() == true);

	c->acquire(v.at(3));

	REQUIRE(v.at(0)->get_is_loaded() == true);
	REQUIRE(v.at(3)->get_is_loaded() == true);

	std::cout << "cachepp|concurrentcache-singlethread: " << c->get_miss_rate() << std::endl;
}
/**
TEST_CASE("cachepp|concurrentcache-multithread") {
	size_t n_threads = 16;
	size_t n_attempts = 1000;

	std::shared_ptr<cachepp::SimpleConcurrentCache<cachepp::SimpleLine>> c (new cachepp::SimpleConcurrentCache<cachepp::SimpleLine>(2));
	std::shared_ptr<std::vector<std::shared_ptr<cachepp::SimpleLine>>> v (new std::vector<std::shared_ptr<cachepp::SimpleLine>> (0));

	for(size_t i = 0; i < 10; ++i) {
		v->push_back(std::shared_ptr<cachepp::SimpleLine> (new cachepp::SimpleLine(i, false)));
	}

	std::vector<std::thread> threads;

	std::shared_ptr<std::atomic<size_t>> result (new std::atomic<size_t>());
	for(size_t attempt = 0; attempt < n_attempts; ++attempt) {
		for(size_t i = 0; i < n_threads; ++i) {
			threads.push_back(std::thread(concurrentcache_multithread_worker, result, c, v));
		}

		for(size_t i = 0; i < n_threads; ++i) {
			threads.at(i).join();
		}
	}

	REQUIRE(*result == (n_attempts * n_threads));
}
*/
<|endoftext|>


<commit_before>//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Stmt class and statement subclasses.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/Stmt.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/IdentifierTable.h"
using namespace clang;

static struct StmtClassNameTable {
  const char *Name;
  unsigned Counter;
  unsigned Size;
} StmtClassInfo[Stmt::lastExprConstant+1];

static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
  static bool Initialized = false;
  if (Initialized)
    return StmtClassInfo[E];

  // Intialize the table on the first use.
  Initialized = true;
#define STMT(N, CLASS, PARENT) \
  StmtClassInfo[N].Name = #CLASS; \
  StmtClassInfo[N].Size = sizeof(CLASS);
#include "clang/AST/StmtNodes.def"

  return StmtClassInfo[E];
}

const char *Stmt::getStmtClassName() const {
  return getStmtInfoTableEntry(sClass).Name;
}

void Stmt::DestroyChildren(ASTContext& C) {
  for (child_iterator I = child_begin(), E = child_end(); I !=E; ++I)
    if (Stmt* Child = *I) Child->Destroy(C);
}

void Stmt::Destroy(ASTContext& C) {
  DestroyChildren(C);
  // FIXME: Eventually all Stmts should be allocated with the allocator
  //  in ASTContext, just like with Decls.
  // this->~Stmt();
  delete this;
}

void DeclStmt::Destroy(ASTContext& C) {
  TheDecl->Destroy(C);
  delete this;
}

void Stmt::PrintStats() {
  // Ensure the table is primed.
  getStmtInfoTableEntry(Stmt::NullStmtClass);

  unsigned sum = 0;
  fprintf(stderr, "*** Stmt/Expr Stats:\n");
  for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
    if (StmtClassInfo[i].Name == 0) continue;
    sum += StmtClassInfo[i].Counter;
  }
  fprintf(stderr, "  %d stmts/exprs total.\n", sum);
  sum = 0;
  for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
    if (StmtClassInfo[i].Name == 0) continue;
    fprintf(stderr, "    %d %s, %d each (%d bytes)\n",
            StmtClassInfo[i].Counter, StmtClassInfo[i].Name,
            StmtClassInfo[i].Size,
            StmtClassInfo[i].Counter*StmtClassInfo[i].Size);
    sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
  }
  fprintf(stderr, "Total bytes = %d\n", sum);
}

void Stmt::addStmtClass(StmtClass s) {
  ++getStmtInfoTableEntry(s).Counter;
}

static bool StatSwitch = false;

bool Stmt::CollectingStats(bool enable) {
  if (enable) StatSwitch = true;
  return StatSwitch;
}

const char *LabelStmt::getName() const {
  return getID()->getName();
}

// This is defined here to avoid polluting Stmt.h with importing Expr.h
SourceRange ReturnStmt::getSourceRange() const {
  if (RetExpr)
    return SourceRange(RetLoc, RetExpr->getLocEnd());
  else
    return SourceRange(RetLoc);
}

bool Stmt::hasImplicitControlFlow() const {
  switch (sClass) {
    default:
      return false;

    case CallExprClass:
    case ConditionalOperatorClass:
    case ChooseExprClass:
    case StmtExprClass:
    case DeclStmtClass:
      return true;

    case Stmt::BinaryOperatorClass: {
      const BinaryOperator* B = cast<BinaryOperator>(this);
      if (B->isLogicalOp() || B->getOpcode() == BinaryOperator::Comma)
        return true;
      else
        return false;
    }
  }
}

//===----------------------------------------------------------------------===//
// Constructors
//===----------------------------------------------------------------------===//

AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
                 unsigned numoutputs, unsigned numinputs,
                 std::string *names, StringLiteral **constraints,
                 Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
                 StringLiteral **clobbers, SourceLocation rparenloc)
  : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
  , IsSimple(issimple), IsVolatile(isvolatile)
  , NumOutputs(numoutputs), NumInputs(numinputs) {
  for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) {
    Names.push_back(names[i]);
    Exprs.push_back(exprs[i]);
    Constraints.push_back(constraints[i]);
  }

  for (unsigned i = 0; i != numclobbers; i++)
    Clobbers.push_back(clobbers[i]);
}

ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
                                             Stmt *Body,  SourceLocation FCL,
                                             SourceLocation RPL)
: Stmt(ObjCForCollectionStmtClass) {
  SubExprs[ELEM] = Elem;
  SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect);
  SubExprs[BODY] = Body;
  ForLoc = FCL;
  RParenLoc = RPL;
}

ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
                                 SourceLocation rparenloc,
                                 Stmt *catchVarStmtDecl, Stmt *atCatchStmt,
                                 Stmt *atCatchList)
: Stmt(ObjCAtCatchStmtClass) {
  SubExprs[SELECTOR] = catchVarStmtDecl;
  SubExprs[BODY] = atCatchStmt;
  SubExprs[NEXT_CATCH] = NULL;
  if (atCatchList) {
    ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList);

    while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt())
      AtCatchList = NextCatch;

    AtCatchList->SubExprs[NEXT_CATCH] = this;
  }
  AtCatchLoc = atCatchLoc;
  RParenLoc = rparenloc;
}

//===----------------------------------------------------------------------===//
//  Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//

// DeclStmt
Stmt::child_iterator DeclStmt::child_begin() { return getDecl(); }
Stmt::child_iterator DeclStmt::child_end() { return child_iterator(); }

DeclStmt::decl_iterator& DeclStmt::decl_iterator::operator++() {
  D = D->getNextDeclarator();
  return *this;
}

// NullStmt
Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator NullStmt::child_end() { return child_iterator(); }

// CompoundStmt
Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; }
Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+Body.size(); }

// CaseStmt
Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; }

// DefaultStmt
Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; }
Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; }

// LabelStmt
Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; }

// IfStmt
Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// SwitchStmt
Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// WhileStmt
Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// DoStmt
Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// ForStmt
Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// ObjCForCollectionStmt
Stmt::child_iterator ObjCForCollectionStmt::child_begin() {
  return &SubExprs[0];
}
Stmt::child_iterator ObjCForCollectionStmt::child_end() {
  return &SubExprs[0]+END_EXPR;
}

// GotoStmt
Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); }

// IndirectGotoStmt
Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); }
const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); }

Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; }
Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; }

// ContinueStmt
Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); }

// BreakStmt
Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); }

// ReturnStmt
const Expr* ReturnStmt::getRetValue() const {
  return cast_or_null<Expr>(RetExpr);
}
Expr* ReturnStmt::getRetValue() {
  return cast_or_null<Expr>(RetExpr);
}

Stmt::child_iterator ReturnStmt::child_begin() {
  return &RetExpr;
}
Stmt::child_iterator ReturnStmt::child_end() {
  return RetExpr ? &RetExpr+1 : &RetExpr;
}

// AsmStmt
Stmt::child_iterator AsmStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator AsmStmt::child_end() { return child_iterator(); }

// ObjCAtCatchStmt
Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator ObjCAtCatchStmt::child_end() {
  return &SubExprs[0]+END_EXPR;
}

// ObjCAtFinallyStmt
Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }

// ObjCAtTryStmt
Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; }
Stmt::child_iterator ObjCAtTryStmt::child_end()   {
  return &SubStmts[0]+END_EXPR;
}

// ObjCAtThrowStmt
Stmt::child_iterator ObjCAtThrowStmt::child_begin() {
  return &Throw;
}

Stmt::child_iterator ObjCAtThrowStmt::child_end() {
  return &Throw+1;
}

// ObjCAtSynchronizedStmt
Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() {
  return &SubStmts[0];
}

Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() {
  return &SubStmts[0]+END_EXPR;
}

<commit_msg>remove spaces at eol to test commit access<commit_after>//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Stmt class and statement subclasses.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/Stmt.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/IdentifierTable.h"
using namespace clang;

static struct StmtClassNameTable {
  const char *Name;
  unsigned Counter;
  unsigned Size;
} StmtClassInfo[Stmt::lastExprConstant+1];

static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
  static bool Initialized = false;
  if (Initialized)
    return StmtClassInfo[E];

  // Intialize the table on the first use.
  Initialized = true;
#define STMT(N, CLASS, PARENT) \
  StmtClassInfo[N].Name = #CLASS; \
  StmtClassInfo[N].Size = sizeof(CLASS);
#include "clang/AST/StmtNodes.def"

  return StmtClassInfo[E];
}

const char *Stmt::getStmtClassName() const {
  return getStmtInfoTableEntry(sClass).Name;
}

void Stmt::DestroyChildren(ASTContext& C) {
  for (child_iterator I = child_begin(), E = child_end(); I !=E; ++I)
    if (Stmt* Child = *I) Child->Destroy(C);
}

void Stmt::Destroy(ASTContext& C) {
  DestroyChildren(C);
  // FIXME: Eventually all Stmts should be allocated with the allocator
  //  in ASTContext, just like with Decls.
  // this->~Stmt();
  delete this;
}

void DeclStmt::Destroy(ASTContext& C) {
  TheDecl->Destroy(C);
  delete this;
}

void Stmt::PrintStats() {
  // Ensure the table is primed.
  getStmtInfoTableEntry(Stmt::NullStmtClass);

  unsigned sum = 0;
  fprintf(stderr, "*** Stmt/Expr Stats:\n");
  for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
    if (StmtClassInfo[i].Name == 0) continue;
    sum += StmtClassInfo[i].Counter;
  }
  fprintf(stderr, "  %d stmts/exprs total.\n", sum);
  sum = 0;
  for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
    if (StmtClassInfo[i].Name == 0) continue;
    fprintf(stderr, "    %d %s, %d each (%d bytes)\n",
            StmtClassInfo[i].Counter, StmtClassInfo[i].Name,
            StmtClassInfo[i].Size,
            StmtClassInfo[i].Counter*StmtClassInfo[i].Size);
    sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
  }
  fprintf(stderr, "Total bytes = %d\n", sum);
}

void Stmt::addStmtClass(StmtClass s) {
  ++getStmtInfoTableEntry(s).Counter;
}

static bool StatSwitch = false;

bool Stmt::CollectingStats(bool enable) {
  if (enable) StatSwitch = true;
  return StatSwitch;
}

const char *LabelStmt::getName() const {
  return getID()->getName();
}

// This is defined here to avoid polluting Stmt.h with importing Expr.h
SourceRange ReturnStmt::getSourceRange() const {
  if (RetExpr)
    return SourceRange(RetLoc, RetExpr->getLocEnd());
  else
    return SourceRange(RetLoc);
}

bool Stmt::hasImplicitControlFlow() const {
  switch (sClass) {
    default:
      return false;

    case CallExprClass:
    case ConditionalOperatorClass:
    case ChooseExprClass:
    case StmtExprClass:
    case DeclStmtClass:
      return true;

    case Stmt::BinaryOperatorClass: {
      const BinaryOperator* B = cast<BinaryOperator>(this);
      if (B->isLogicalOp() || B->getOpcode() == BinaryOperator::Comma)
        return true;
      else
        return false;
    }
  }
}

//===----------------------------------------------------------------------===//
// Constructors
//===----------------------------------------------------------------------===//

AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
                 unsigned numoutputs, unsigned numinputs,
                 std::string *names, StringLiteral **constraints,
                 Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
                 StringLiteral **clobbers, SourceLocation rparenloc)
  : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
  , IsSimple(issimple), IsVolatile(isvolatile)
  , NumOutputs(numoutputs), NumInputs(numinputs) {
  for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) {
    Names.push_back(names[i]);
    Exprs.push_back(exprs[i]);
    Constraints.push_back(constraints[i]);
  }

  for (unsigned i = 0; i != numclobbers; i++)
    Clobbers.push_back(clobbers[i]);
}

ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
                                             Stmt *Body,  SourceLocation FCL,
                                             SourceLocation RPL)
: Stmt(ObjCForCollectionStmtClass) {
  SubExprs[ELEM] = Elem;
  SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect);
  SubExprs[BODY] = Body;
  ForLoc = FCL;
  RParenLoc = RPL;
}

ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
                                 SourceLocation rparenloc,
                                 Stmt *catchVarStmtDecl, Stmt *atCatchStmt,
                                 Stmt *atCatchList)
: Stmt(ObjCAtCatchStmtClass) {
  SubExprs[SELECTOR] = catchVarStmtDecl;
  SubExprs[BODY] = atCatchStmt;
  SubExprs[NEXT_CATCH] = NULL;
  if (atCatchList) {
    ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList);

    while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt())
      AtCatchList = NextCatch;

    AtCatchList->SubExprs[NEXT_CATCH] = this;
  }
  AtCatchLoc = atCatchLoc;
  RParenLoc = rparenloc;
}

//===----------------------------------------------------------------------===//
//  Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//

// DeclStmt
Stmt::child_iterator DeclStmt::child_begin() { return getDecl(); }
Stmt::child_iterator DeclStmt::child_end() { return child_iterator(); }

DeclStmt::decl_iterator& DeclStmt::decl_iterator::operator++() {
  D = D->getNextDeclarator();
  return *this;
}

// NullStmt
Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator NullStmt::child_end() { return child_iterator(); }

// CompoundStmt
Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; }
Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+Body.size(); }

// CaseStmt
Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; }

// DefaultStmt
Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; }
Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; }

// LabelStmt
Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; }

// IfStmt
Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// SwitchStmt
Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// WhileStmt
Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// DoStmt
Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// ForStmt
Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; }

// ObjCForCollectionStmt
Stmt::child_iterator ObjCForCollectionStmt::child_begin() {
  return &SubExprs[0];
}
Stmt::child_iterator ObjCForCollectionStmt::child_end() {
  return &SubExprs[0]+END_EXPR;
}

// GotoStmt
Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); }

// IndirectGotoStmt
Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); }
const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); }

Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; }
Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; }

// ContinueStmt
Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); }

// BreakStmt
Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); }

// ReturnStmt
const Expr* ReturnStmt::getRetValue() const {
  return cast_or_null<Expr>(RetExpr);
}
Expr* ReturnStmt::getRetValue() {
  return cast_or_null<Expr>(RetExpr);
}

Stmt::child_iterator ReturnStmt::child_begin() {
  return &RetExpr;
}
Stmt::child_iterator ReturnStmt::child_end() {
  return RetExpr ? &RetExpr+1 : &RetExpr;
}

// AsmStmt
Stmt::child_iterator AsmStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator AsmStmt::child_end() { return child_iterator(); }

// ObjCAtCatchStmt
Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator ObjCAtCatchStmt::child_end() {
  return &SubExprs[0]+END_EXPR;
}

// ObjCAtFinallyStmt
Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }

// ObjCAtTryStmt
Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; }
Stmt::child_iterator ObjCAtTryStmt::child_end()   {
  return &SubStmts[0]+END_EXPR;
}

// ObjCAtThrowStmt
Stmt::child_iterator ObjCAtThrowStmt::child_begin() {
  return &Throw;
}

Stmt::child_iterator ObjCAtThrowStmt::child_end() {
  return &Throw+1;
}

// ObjCAtSynchronizedStmt
Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() {
  return &SubStmts[0];
}

Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() {
  return &SubStmts[0]+END_EXPR;
}

<|endoftext|>