<commit_before>#include "nw_screen_api.h"

#if defined(OS_WIN)
#include "windows.h"
#endif

#include "base/lazy_instance.h"
#include "base/values.h"
#include "content/nw/src/api/nw_screen.h"
#include "extensions/browser/extensions_browser_client.h"
#include "ui/display/display_observer.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"

// For desktop capture APIs
#include "base/base64.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/media/webrtc/desktop_media_list_observer.h"
#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
#include "chrome/browser/media/webrtc/native_desktop_media_list.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/desktop_streams_registry.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"

using namespace extensions::nwapi::nw__screen;
using namespace content;

namespace extensions {

  class NwDesktopCaptureMonitor : public DesktopMediaListObserver {
  public:
    static NwDesktopCaptureMonitor* GetInstance();

    NwDesktopCaptureMonitor();
    void Start(bool screens, bool windows);
    void Stop();
    bool IsStarted();

  private:
    int GetPrimaryMonitorIndex();
    // DesktopMediaListObserver implementation.
    void OnSourceAdded(int index) override;
    void OnSourceRemoved(int index) override;
    void OnSourceMoved(int old_index, int new_index) override;
    void OnSourceNameChanged(int index) override;
    void OnSourceThumbnailChanged(int index) override;
    void OnSourcePreviewChanged(size_t index) override;

    bool started_;
    std::vector<std::unique_ptr<DesktopMediaList>> media_list_;

    DISALLOW_COPY_AND_ASSIGN(NwDesktopCaptureMonitor);
  };

  class NwScreenDisplayObserver: public display::DisplayObserver {
  public:
    static NwScreenDisplayObserver* GetInstance();
    NwScreenDisplayObserver();

  private:
    ~NwScreenDisplayObserver() override;
    // gfx::DisplayObserver implementation.
    void OnDisplayMetricsChanged(const display::Display& display, uint32_t changed_metrics) override;
    void OnDisplayAdded(const display::Display& new_display) override;
    void OnDisplayRemoved(const display::Display& old_display) override;

    DISALLOW_COPY_AND_ASSIGN(NwScreenDisplayObserver);
  };

  namespace {

    // Helper function to convert display::Display to nwapi::nw__screen::Display
    std::unique_ptr<nwapi::nw__screen::Display> ConvertGfxDisplay(const display::Display& gfx_display) {
      std::unique_ptr<nwapi::nw__screen::Display> displayResult(new nwapi::nw__screen::Display);

      displayResult->id = gfx_display.id();
      displayResult->scale_factor = gfx_display.device_scale_factor();
      displayResult->is_built_in = gfx_display.IsInternal();
      displayResult->rotation = gfx_display.RotationAsDegree();
      displayResult->touch_support = (int)gfx_display.touch_support();

      gfx::Rect rect = gfx_display.bounds();
      DisplayGeometry& bounds = displayResult->bounds;
      bounds.x = rect.x();
      bounds.y = rect.y();
      bounds.width = rect.width();
      bounds.height = rect.height();

      rect = gfx_display.work_area();
      DisplayGeometry& work_area = displayResult->work_area;
      work_area.x = rect.x();
      work_area.y = rect.y();
      work_area.width = rect.width();
      work_area.height = rect.height();

      return displayResult;
    }

    void DispatchEvent(
        events::HistogramValue histogram_value,
        const std::string& event_name,
        std::vector<base::Value> args) {
      DCHECK_CURRENTLY_ON(BrowserThread::UI);
      //std::unique_ptr<base::ListValue> arg_list(std::move(args));
      ExtensionsBrowserClient::Get()->
        BroadcastEventToRenderers(
                                  histogram_value, event_name,
                                  std::make_unique<base::ListValue>(std::move(args)),
                                  false);
    }

    // Lazy initialize screen event listeners until first call
    base::LazyInstance<NwScreenDisplayObserver>::Leaky
      g_display_observer = LAZY_INSTANCE_INITIALIZER;

    base::LazyInstance<NwDesktopCaptureMonitor>::Leaky
      g_desktop_capture_monitor = LAZY_INSTANCE_INITIALIZER;

  }

  // static
  NwScreenDisplayObserver* NwScreenDisplayObserver::GetInstance() {
    return g_display_observer.Pointer();
  }

  NwScreenDisplayObserver::NwScreenDisplayObserver() {
    display::Screen* screen = display::Screen::GetScreen();
    if (screen) {
      screen->AddObserver(this);
    }
  }

  NwScreenDisplayObserver::~NwScreenDisplayObserver() {
    display::Screen* screen = display::Screen::GetScreen();
    if (screen) {
      screen->RemoveObserver(this);
    }
  }

  // Called when the |display|'s bound has changed.
  void NwScreenDisplayObserver::OnDisplayMetricsChanged(const display::Display& display,
    uint32_t changed_metrics) {
    std::vector<base::Value> args =
      nwapi::nw__screen::OnDisplayBoundsChanged::Create(*ConvertGfxDisplay(display),
                                                        changed_metrics);
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnDisplayBoundsChanged::kEventName,
      std::move(args));
  }

  // Called when |new_display| has been added.
  void NwScreenDisplayObserver::OnDisplayAdded(const display::Display& new_display) {
    std::vector<base::Value> args =
      nwapi::nw__screen::OnDisplayAdded::Create(*ConvertGfxDisplay(new_display));
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnDisplayAdded::kEventName,
      std::move(args));
  }

  // Called when |old_display| has been removed.
  void NwScreenDisplayObserver::OnDisplayRemoved(const display::Display& old_display) {
    std::vector<base::Value> args =
      nwapi::nw__screen::OnDisplayRemoved::Create(*ConvertGfxDisplay(old_display));
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnDisplayRemoved::kEventName,
      std::move(args));
  }

  NwScreenGetScreensFunction::NwScreenGetScreensFunction() {}

  bool NwScreenGetScreensFunction::RunNWSync(base::ListValue* response, std::string* error) {
    const std::vector<display::Display>& displays = display::Screen::GetScreen()->GetAllDisplays();

    for (size_t i=0; i<displays.size(); i++) {
      response->Append(ConvertGfxDisplay(displays[i])->ToValue());
    }

    return true;
  }

  NwScreenInitEventListenersFunction::NwScreenInitEventListenersFunction() {}

  bool NwScreenInitEventListenersFunction::RunNWSync(base::ListValue* response, std::string* error) {
    NwScreenDisplayObserver::GetInstance();
    return true;
  }

  NwDesktopCaptureMonitor* NwDesktopCaptureMonitor::GetInstance() {
    return g_desktop_capture_monitor.Pointer();
  }

  NwDesktopCaptureMonitor::NwDesktopCaptureMonitor()
      : started_(false) {
  }

  void NwDesktopCaptureMonitor::Start(bool screens, bool windows) {
    if (started_) {
      return;
    }

    started_ = true;

    webrtc::DesktopCaptureOptions options = webrtc::DesktopCaptureOptions::CreateDefault();
    options.set_disable_effects(false);

    if (screens) {
      std::unique_ptr<DesktopMediaList> screen_media_list =
        std::make_unique<NativeDesktopMediaList>(
          DesktopMediaList::Type::kScreen,
          webrtc::DesktopCapturer::CreateScreenCapturer(options));
      media_list_.push_back(std::move(screen_media_list));
    }

    if (windows) {
      std::unique_ptr<DesktopMediaList> window_media_list =
        std::make_unique<NativeDesktopMediaList>(
          DesktopMediaList::Type::kWindow,
          webrtc::DesktopCapturer::CreateWindowCapturer(options));
      media_list_.push_back(std::move(window_media_list));
    }

    for (auto& media_list : media_list_) {
      media_list->StartUpdating(this);
    }
  }

  void NwDesktopCaptureMonitor::Stop() {
    started_ = false;
    media_list_.clear();
  }

  bool NwDesktopCaptureMonitor::IsStarted() {
    return started_;
  }

  int NwDesktopCaptureMonitor::GetPrimaryMonitorIndex() {
  #ifdef _WIN32
    int count=0;
    for (int i = 0;; ++i) {
      DISPLAY_DEVICE device;
      device.cb = sizeof(device);
      BOOL ret = EnumDisplayDevices(NULL, i, &device, 0);
      if(!ret)
        break;
      if (device.StateFlags & DISPLAY_DEVICE_ACTIVE){
        if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE){
          return count;
        }
        count++;
      }
    }
  #endif
    return -1;
  }

void NwDesktopCaptureMonitor::OnSourceAdded(int index) {
    DesktopMediaList::Source src = media_list_[0]->GetSource(index);

    std::string type;
    switch(src.id.type) {
    case content::DesktopMediaID::TYPE_WINDOW:
      type = "window";
      break;
    case content::DesktopMediaID::TYPE_SCREEN:
      type = "screen";
      break;
    case content::DesktopMediaID::TYPE_NONE:
      type = "none";
      break;
    default:
      type = "unknown";
      break;
    }

    std::vector<base::Value> args = nwapi::nw__screen::OnSourceAdded::Create(
      src.id.ToString(),
      base::UTF16ToUTF8(src.name),
      index,
      type,
      src.id.type == content::DesktopMediaID::TYPE_SCREEN && GetPrimaryMonitorIndex() == index);

    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnSourceAdded::kEventName,
      std::move(args));
  }

void NwDesktopCaptureMonitor::OnSourceRemoved(int index) {
    std::vector<base::Value> args = nwapi::nw__screen::OnSourceRemoved::Create(index);
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnSourceRemoved::kEventName,
      std::move(args));
  }

void NwDesktopCaptureMonitor::OnSourceMoved(int old_index, int new_index) {
    DesktopMediaList::Source src = media_list_[0]->GetSource(new_index);
    std::vector<base::Value> args = nwapi::nw__screen::OnSourceOrderChanged::Create(
      src.id.ToString(),
      new_index,
      old_index);
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnSourceOrderChanged::kEventName,
      std::move(args));
  }

void NwDesktopCaptureMonitor::OnSourceNameChanged(int index) {
    DesktopMediaList::Source src = media_list_[0]->GetSource(index);
    std::vector<base::Value> args = nwapi::nw__screen::OnSourceNameChanged::Create(
      src.id.ToString(),
      base::UTF16ToUTF8(src.name));
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnSourceNameChanged::kEventName,
      std::move(args));
  }

void NwDesktopCaptureMonitor::OnSourcePreviewChanged(size_t index) {
}

void NwDesktopCaptureMonitor::OnSourceThumbnailChanged(int index) {
    std::string base64;

    DesktopMediaList::Source src = media_list_[0]->GetSource(index);
    SkBitmap bitmap = src.thumbnail.GetRepresentation(1).GetBitmap();
    std::vector<unsigned char> data;
    bool success = gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &data);
    if (success){
      base::StringPiece raw_str(reinterpret_cast<const char*>(&data[0]), data.size());
      base::Base64Encode(raw_str, &base64);
    }

    std::vector<base::Value> args = nwapi::nw__screen::OnSourceThumbnailChanged::Create(
      src.id.ToString(),
      base64);
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnSourceThumbnailChanged::kEventName,
      std::move(args));
  }

  NwScreenStartMonitorFunction::NwScreenStartMonitorFunction() {}

  bool NwScreenStartMonitorFunction::RunNWSync(base::ListValue* response, std::string* error) {
    bool screens, windows;
    EXTENSION_FUNCTION_VALIDATE(args().size() >= 2);
    EXTENSION_FUNCTION_VALIDATE(args()[0].is_bool() && args()[1].is_bool());
    screens = args()[0].GetBool();
    windows = args()[1].GetBool();
    NwDesktopCaptureMonitor::GetInstance()->Start(screens, windows);
    return true;
  }

  NwScreenStopMonitorFunction::NwScreenStopMonitorFunction() {}

  bool NwScreenStopMonitorFunction::RunNWSync(base::ListValue* response, std::string* error) {
    NwDesktopCaptureMonitor::GetInstance()->Stop();
    return true;
  }

  NwScreenIsMonitorStartedFunction::NwScreenIsMonitorStartedFunction() {}

  bool NwScreenIsMonitorStartedFunction::RunNWSync(base::ListValue* response, std::string* error) {
    response->Append(NwDesktopCaptureMonitor::GetInstance()->IsStarted());
    return true;
  }

  NwScreenRegisterStreamFunction::NwScreenRegisterStreamFunction() {}

  bool NwScreenRegisterStreamFunction::RunNWSync(base::ListValue* response, std::string* error) {
    std::string id;
    EXTENSION_FUNCTION_VALIDATE(args().size() >= 1);
    EXTENSION_FUNCTION_VALIDATE(args()[0].is_string());
    id = args()[0].GetString();

    // following code is modified from `DesktopCaptureChooseDesktopMediaFunctionBase::OnPickerDialogResults`
    // in chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc

    content::DesktopMediaID source = content::DesktopMediaID::Parse(id);
    content::WebContents* web_contents = GetSenderWebContents();
    if (!source.is_null() && web_contents) {
      std::string result;
      source.audio_share = true;
      content::DesktopStreamsRegistry* registry = content::DesktopStreamsRegistry::GetInstance();
      // TODO(miu): Once render_frame_host() is being set, we should register the
      // exact RenderFrame requesting the stream, not the main RenderFrame.  With
      // that change, also update
      // MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest().
      // http://crbug.com/304341
      content::RenderFrameHost* const main_frame = web_contents->GetMainFrame();
      result = registry->RegisterStream(main_frame->GetProcess()->GetID(),
                                        main_frame->GetRoutingID(),
                                        url::Origin::Create(web_contents->GetURL().GetOrigin()),
                                        source,
                                        extension()->name(), content::kRegistryStreamTypeDesktop);
      response->Append(result);
    }
    return true;
  }

} // extensions
<commit_msg>migrate from GetOrigin()<commit_after>#include "nw_screen_api.h"

#if defined(OS_WIN)
#include "windows.h"
#endif

#include "base/lazy_instance.h"
#include "base/values.h"
#include "content/nw/src/api/nw_screen.h"
#include "extensions/browser/extensions_browser_client.h"
#include "ui/display/display_observer.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"

// For desktop capture APIs
#include "base/base64.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/media/webrtc/desktop_media_list_observer.h"
#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
#include "chrome/browser/media/webrtc/native_desktop_media_list.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/desktop_streams_registry.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"

using namespace extensions::nwapi::nw__screen;
using namespace content;

namespace extensions {

  class NwDesktopCaptureMonitor : public DesktopMediaListObserver {
  public:
    static NwDesktopCaptureMonitor* GetInstance();

    NwDesktopCaptureMonitor();
    void Start(bool screens, bool windows);
    void Stop();
    bool IsStarted();

  private:
    int GetPrimaryMonitorIndex();
    // DesktopMediaListObserver implementation.
    void OnSourceAdded(int index) override;
    void OnSourceRemoved(int index) override;
    void OnSourceMoved(int old_index, int new_index) override;
    void OnSourceNameChanged(int index) override;
    void OnSourceThumbnailChanged(int index) override;
    void OnSourcePreviewChanged(size_t index) override;

    bool started_;
    std::vector<std::unique_ptr<DesktopMediaList>> media_list_;

    DISALLOW_COPY_AND_ASSIGN(NwDesktopCaptureMonitor);
  };

  class NwScreenDisplayObserver: public display::DisplayObserver {
  public:
    static NwScreenDisplayObserver* GetInstance();
    NwScreenDisplayObserver();

  private:
    ~NwScreenDisplayObserver() override;
    // gfx::DisplayObserver implementation.
    void OnDisplayMetricsChanged(const display::Display& display, uint32_t changed_metrics) override;
    void OnDisplayAdded(const display::Display& new_display) override;
    void OnDisplayRemoved(const display::Display& old_display) override;

    DISALLOW_COPY_AND_ASSIGN(NwScreenDisplayObserver);
  };

  namespace {

    // Helper function to convert display::Display to nwapi::nw__screen::Display
    std::unique_ptr<nwapi::nw__screen::Display> ConvertGfxDisplay(const display::Display& gfx_display) {
      std::unique_ptr<nwapi::nw__screen::Display> displayResult(new nwapi::nw__screen::Display);

      displayResult->id = gfx_display.id();
      displayResult->scale_factor = gfx_display.device_scale_factor();
      displayResult->is_built_in = gfx_display.IsInternal();
      displayResult->rotation = gfx_display.RotationAsDegree();
      displayResult->touch_support = (int)gfx_display.touch_support();

      gfx::Rect rect = gfx_display.bounds();
      DisplayGeometry& bounds = displayResult->bounds;
      bounds.x = rect.x();
      bounds.y = rect.y();
      bounds.width = rect.width();
      bounds.height = rect.height();

      rect = gfx_display.work_area();
      DisplayGeometry& work_area = displayResult->work_area;
      work_area.x = rect.x();
      work_area.y = rect.y();
      work_area.width = rect.width();
      work_area.height = rect.height();

      return displayResult;
    }

    void DispatchEvent(
        events::HistogramValue histogram_value,
        const std::string& event_name,
        std::vector<base::Value> args) {
      DCHECK_CURRENTLY_ON(BrowserThread::UI);
      //std::unique_ptr<base::ListValue> arg_list(std::move(args));
      ExtensionsBrowserClient::Get()->
        BroadcastEventToRenderers(
                                  histogram_value, event_name,
                                  std::make_unique<base::ListValue>(std::move(args)),
                                  false);
    }

    // Lazy initialize screen event listeners until first call
    base::LazyInstance<NwScreenDisplayObserver>::Leaky
      g_display_observer = LAZY_INSTANCE_INITIALIZER;

    base::LazyInstance<NwDesktopCaptureMonitor>::Leaky
      g_desktop_capture_monitor = LAZY_INSTANCE_INITIALIZER;

  }

  // static
  NwScreenDisplayObserver* NwScreenDisplayObserver::GetInstance() {
    return g_display_observer.Pointer();
  }

  NwScreenDisplayObserver::NwScreenDisplayObserver() {
    display::Screen* screen = display::Screen::GetScreen();
    if (screen) {
      screen->AddObserver(this);
    }
  }

  NwScreenDisplayObserver::~NwScreenDisplayObserver() {
    display::Screen* screen = display::Screen::GetScreen();
    if (screen) {
      screen->RemoveObserver(this);
    }
  }

  // Called when the |display|'s bound has changed.
  void NwScreenDisplayObserver::OnDisplayMetricsChanged(const display::Display& display,
    uint32_t changed_metrics) {
    std::vector<base::Value> args =
      nwapi::nw__screen::OnDisplayBoundsChanged::Create(*ConvertGfxDisplay(display),
                                                        changed_metrics);
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnDisplayBoundsChanged::kEventName,
      std::move(args));
  }

  // Called when |new_display| has been added.
  void NwScreenDisplayObserver::OnDisplayAdded(const display::Display& new_display) {
    std::vector<base::Value> args =
      nwapi::nw__screen::OnDisplayAdded::Create(*ConvertGfxDisplay(new_display));
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnDisplayAdded::kEventName,
      std::move(args));
  }

  // Called when |old_display| has been removed.
  void NwScreenDisplayObserver::OnDisplayRemoved(const display::Display& old_display) {
    std::vector<base::Value> args =
      nwapi::nw__screen::OnDisplayRemoved::Create(*ConvertGfxDisplay(old_display));
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnDisplayRemoved::kEventName,
      std::move(args));
  }

  NwScreenGetScreensFunction::NwScreenGetScreensFunction() {}

  bool NwScreenGetScreensFunction::RunNWSync(base::ListValue* response, std::string* error) {
    const std::vector<display::Display>& displays = display::Screen::GetScreen()->GetAllDisplays();

    for (size_t i=0; i<displays.size(); i++) {
      response->Append(ConvertGfxDisplay(displays[i])->ToValue());
    }

    return true;
  }

  NwScreenInitEventListenersFunction::NwScreenInitEventListenersFunction() {}

  bool NwScreenInitEventListenersFunction::RunNWSync(base::ListValue* response, std::string* error) {
    NwScreenDisplayObserver::GetInstance();
    return true;
  }

  NwDesktopCaptureMonitor* NwDesktopCaptureMonitor::GetInstance() {
    return g_desktop_capture_monitor.Pointer();
  }

  NwDesktopCaptureMonitor::NwDesktopCaptureMonitor()
      : started_(false) {
  }

  void NwDesktopCaptureMonitor::Start(bool screens, bool windows) {
    if (started_) {
      return;
    }

    started_ = true;

    webrtc::DesktopCaptureOptions options = webrtc::DesktopCaptureOptions::CreateDefault();
    options.set_disable_effects(false);

    if (screens) {
      std::unique_ptr<DesktopMediaList> screen_media_list =
        std::make_unique<NativeDesktopMediaList>(
          DesktopMediaList::Type::kScreen,
          webrtc::DesktopCapturer::CreateScreenCapturer(options));
      media_list_.push_back(std::move(screen_media_list));
    }

    if (windows) {
      std::unique_ptr<DesktopMediaList> window_media_list =
        std::make_unique<NativeDesktopMediaList>(
          DesktopMediaList::Type::kWindow,
          webrtc::DesktopCapturer::CreateWindowCapturer(options));
      media_list_.push_back(std::move(window_media_list));
    }

    for (auto& media_list : media_list_) {
      media_list->StartUpdating(this);
    }
  }

  void NwDesktopCaptureMonitor::Stop() {
    started_ = false;
    media_list_.clear();
  }

  bool NwDesktopCaptureMonitor::IsStarted() {
    return started_;
  }

  int NwDesktopCaptureMonitor::GetPrimaryMonitorIndex() {
  #ifdef _WIN32
    int count=0;
    for (int i = 0;; ++i) {
      DISPLAY_DEVICE device;
      device.cb = sizeof(device);
      BOOL ret = EnumDisplayDevices(NULL, i, &device, 0);
      if(!ret)
        break;
      if (device.StateFlags & DISPLAY_DEVICE_ACTIVE){
        if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE){
          return count;
        }
        count++;
      }
    }
  #endif
    return -1;
  }

void NwDesktopCaptureMonitor::OnSourceAdded(int index) {
    DesktopMediaList::Source src = media_list_[0]->GetSource(index);

    std::string type;
    switch(src.id.type) {
    case content::DesktopMediaID::TYPE_WINDOW:
      type = "window";
      break;
    case content::DesktopMediaID::TYPE_SCREEN:
      type = "screen";
      break;
    case content::DesktopMediaID::TYPE_NONE:
      type = "none";
      break;
    default:
      type = "unknown";
      break;
    }

    std::vector<base::Value> args = nwapi::nw__screen::OnSourceAdded::Create(
      src.id.ToString(),
      base::UTF16ToUTF8(src.name),
      index,
      type,
      src.id.type == content::DesktopMediaID::TYPE_SCREEN && GetPrimaryMonitorIndex() == index);

    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnSourceAdded::kEventName,
      std::move(args));
  }

void NwDesktopCaptureMonitor::OnSourceRemoved(int index) {
    std::vector<base::Value> args = nwapi::nw__screen::OnSourceRemoved::Create(index);
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnSourceRemoved::kEventName,
      std::move(args));
  }

void NwDesktopCaptureMonitor::OnSourceMoved(int old_index, int new_index) {
    DesktopMediaList::Source src = media_list_[0]->GetSource(new_index);
    std::vector<base::Value> args = nwapi::nw__screen::OnSourceOrderChanged::Create(
      src.id.ToString(),
      new_index,
      old_index);
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnSourceOrderChanged::kEventName,
      std::move(args));
  }

void NwDesktopCaptureMonitor::OnSourceNameChanged(int index) {
    DesktopMediaList::Source src = media_list_[0]->GetSource(index);
    std::vector<base::Value> args = nwapi::nw__screen::OnSourceNameChanged::Create(
      src.id.ToString(),
      base::UTF16ToUTF8(src.name));
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnSourceNameChanged::kEventName,
      std::move(args));
  }

void NwDesktopCaptureMonitor::OnSourcePreviewChanged(size_t index) {
}

void NwDesktopCaptureMonitor::OnSourceThumbnailChanged(int index) {
    std::string base64;

    DesktopMediaList::Source src = media_list_[0]->GetSource(index);
    SkBitmap bitmap = src.thumbnail.GetRepresentation(1).GetBitmap();
    std::vector<unsigned char> data;
    bool success = gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &data);
    if (success){
      base::StringPiece raw_str(reinterpret_cast<const char*>(&data[0]), data.size());
      base::Base64Encode(raw_str, &base64);
    }

    std::vector<base::Value> args = nwapi::nw__screen::OnSourceThumbnailChanged::Create(
      src.id.ToString(),
      base64);
    DispatchEvent(
      events::HistogramValue::UNKNOWN,
      nwapi::nw__screen::OnSourceThumbnailChanged::kEventName,
      std::move(args));
  }

  NwScreenStartMonitorFunction::NwScreenStartMonitorFunction() {}

  bool NwScreenStartMonitorFunction::RunNWSync(base::ListValue* response, std::string* error) {
    bool screens, windows;
    EXTENSION_FUNCTION_VALIDATE(args().size() >= 2);
    EXTENSION_FUNCTION_VALIDATE(args()[0].is_bool() && args()[1].is_bool());
    screens = args()[0].GetBool();
    windows = args()[1].GetBool();
    NwDesktopCaptureMonitor::GetInstance()->Start(screens, windows);
    return true;
  }

  NwScreenStopMonitorFunction::NwScreenStopMonitorFunction() {}

  bool NwScreenStopMonitorFunction::RunNWSync(base::ListValue* response, std::string* error) {
    NwDesktopCaptureMonitor::GetInstance()->Stop();
    return true;
  }

  NwScreenIsMonitorStartedFunction::NwScreenIsMonitorStartedFunction() {}

  bool NwScreenIsMonitorStartedFunction::RunNWSync(base::ListValue* response, std::string* error) {
    response->Append(NwDesktopCaptureMonitor::GetInstance()->IsStarted());
    return true;
  }

  NwScreenRegisterStreamFunction::NwScreenRegisterStreamFunction() {}

  bool NwScreenRegisterStreamFunction::RunNWSync(base::ListValue* response, std::string* error) {
    std::string id;
    EXTENSION_FUNCTION_VALIDATE(args().size() >= 1);
    EXTENSION_FUNCTION_VALIDATE(args()[0].is_string());
    id = args()[0].GetString();

    // following code is modified from `DesktopCaptureChooseDesktopMediaFunctionBase::OnPickerDialogResults`
    // in chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc

    content::DesktopMediaID source = content::DesktopMediaID::Parse(id);
    content::WebContents* web_contents = GetSenderWebContents();
    if (!source.is_null() && web_contents) {
      std::string result;
      source.audio_share = true;
      content::DesktopStreamsRegistry* registry = content::DesktopStreamsRegistry::GetInstance();
      // TODO(miu): Once render_frame_host() is being set, we should register the
      // exact RenderFrame requesting the stream, not the main RenderFrame.  With
      // that change, also update
      // MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest().
      // http://crbug.com/304341
      content::RenderFrameHost* const main_frame = web_contents->GetMainFrame();
      result = registry->RegisterStream(main_frame->GetProcess()->GetID(),
                                        main_frame->GetRoutingID(),
                                        url::Origin::Create(web_contents->GetURL().DeprecatedGetOriginAsURL()),
                                        source,
                                        extension()->name(), content::kRegistryStreamTypeDesktop);
      response->Append(result);
    }
    return true;
  }

} // extensions
<|endoftext|>


<commit_before>// Copied from public information at: http://www.evl.uic.edu/pape/CAVE/prog/
//
// Thanks Dave.
//
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <drivers/Open/Trackd/trackdmem.h>

#if !defined(VPR_OS_Windows)
#include <sys/ipc.h>
#include <sys/shm.h>
#endif

// ===========================================================================
// trackd tracker API

struct TrackerConnection
{
#if defined(VPR_OS_Windows)
   HANDLE                     file_mapping;
   CAVE_TRACKDTRACKER_HEADER* tracker;
#else
   int
   CAVE_TRACKDTRACKER_HEADER* tracker;
#endif
};

TrackerConnection*
trackd_tracker_attach(int shmKey)
{
   TrackerConnection* t = new TrackerConnection();

#if defined(VPR_OS_Windows)
   char shmfile[256];
   sprintf(shmfile, "%d", shmKey);
   t->file_mapping = OpenFileMapping(FILE_MAP_READ, FALSE, shmfile);

   if(!t->file_mapping)
   {
      fprintf(stderr, "ERROR: cannot get tracker shared memory\n");
      perror("OpenFileMapping");
      return NULL;
   }

   t->tracker =
      reinterpret_cast<CAVE_TRACKDTRACKER_HEADER*>(
         MapViewOfFile(t->file_mapping, FILE_MAP_READ, 0, 0, 0));

   if(!t->tracker)
   {
      fprintf(stderr, "ERROR: cannot attach tracker shared memory\n");
      perror("MapViewOfFile");
      return NULL;
   }
#else
   t->shmid = shmget(shmKey, sizeof(CAVE_TRACKDTRACKER_HEADER), 0);

   if(t->shmid < 0)
   {
      fprintf(stderr,"ERROR: can't get tracker shared memory\n");
      perror("shmget");
      return NULL;
   }

   t->tracker =
      reinterpret_cast<CAVE_TRACKDTRACKER_HEADER*>(
         shmat(t->shmid, (void *) 0, 0));

   if(t->tracker == reinterpret_cast<CAVE_TRACKDTRACKER_HEADER*>(-1))
   {
      fprintf(stderr,"ERROR: can't attach tracker shared memory\n");
      perror("shmat");
      return NULL;
   }
#endif

   return t;
}

void
trackd_tracker_release(TrackerConnection* t)
{
#if defined(VPR_OS_Windows)
   if(t && t->tracker)
   {
      UnmapViewOfFile(t->tracker);
      CloseHandle(t->file_mapping);
   }
#else
   if(t && t->tracker)
   {
#  ifdef __sun__
#     if defined(_XOPEN_SOURCE) && (_XOPEN_VERSION - 0 >= 4)
      shmdt(t->tracker);
#     else
      shmdt((char*) t->tracker);
#     endif
#  else
      shmdt(t->tracker);
#  endif
   }
#endif

   delete t;
}

int
trackd_tracker_num_sensors(TrackerConnection* t)
{
   return t->tracker->numSensors;
}

CAVE_SENSOR_ST*
trackd_tracker_sensor(TrackerConnection* t, int sensorNum)
{
   unsigned char* pointer =
      reinterpret_cast<unsigned char*>(t->tracker);

   pointer += t->tracker->sensorOffset + sensorNum * t->tracker->sensorSize;

   return reinterpret_cast<CAVE_SENSOR_ST*>(pointer);
}

// ===========================================================================
// trackd controller API

struct ControllerConnection
{
#if defined(VPR_OS_Windows)
   HANDLE                        file_mapping;
   CAVE_TRACKDCONTROLLER_HEADER* controller;
#else
   int                           shmid;
   CAVE_TRACKDCONTROLLER_HEADER* controller;
#endif
};

ControllerConnection*
trackd_controller_attach(int shmKey)
{
   ControllerConnection* c = new ControllerConnection();

#if defined(VPR_OS_Windows)
   char shmfile[256];
   sprintf(shmfile, "%d", shmKey);
   c->file_mapping = OpenFileMapping(FILE_MAP_READ, FALSE, shmfile);

   if(!c->file_mapping)
   {
      fprintf(stderr, "ERROR: cannot get controller shared memory\n");
      perror("OpenFileMapping");
      return NULL;
   }

   c->controller =
      reinterpret_cast<CAVE_TRACKDCONTROLLER_HEADER*>(
         MapViewOfFile(c->file_mapping, FILE_MAP_READ, 0, 0, 0));

   if(!c->controller)
   {
      fprintf(stderr, "ERROR: cannot attach controller shared memory\n");
      perror("MapViewOfFile");
      return NULL;
   }
#else
   c->shmid = shmget(shmKey, sizeof(CAVE_TRACKDCONTROLLER_HEADER), 0);

   if(c->shmid < 0)
   {
      fprintf(stderr,"ERROR: can't get controller shared memory\n");
      perror("shmget");
      return NULL;
   }

   c->controller =
      reinterpret_cast<CAVE_TRACKDCONTROLLER_HEADER*>(
         shmat(controller_shmid, (void *) 0, 0));

   if(c->controller == (CAVE_TRACKDCONTROLLER_HEADER *) -1)
   {
      fprintf(stderr,"ERROR: can't attach controller shared memory\n");
      perror("shmat");
      return NULL;
   }
#endif

   return c;
}

void
trackd_controller_release(ControllerConnection* c)
{
#if defined(VPR_OS_Windows)
   if(c && c->controller)
   {
      UnmapViewOfFile(c->controller);
      CloseHandle(c->file_mapping);
   }
#else
   if(c && c->controller)
   {
#  ifdef __sun__
#     if defined(_XOPEN_SOURCE) && (_XOPEN_VERSION - 0 >= 4)
      shmdt(c->controller);
#     else
      shmdt((char*) c->controller);
#     endif
#  else
      shmdt(c->controller);
#  endif
   }
#endif

   delete c;
}

int
trackd_controller_num_buttons(ControllerConnection* c)
{
   return c->controller->numButtons;
}

int
trackd_controller_num_valuators(ControllerConnection* c)
{
   return c->controller->numValuators;
}

int
trackd_controller_button(ControllerConnection* c, int buttonNum)
{
   unsigned char* pointer =
      reinterpret_cast<unsigned char*>(c->controller)
      + c->controller->buttonOffset;
   int* buttons = reinterpret_cast<int*>(pointer);

   return buttons[buttonNum];
}

float
trackd_controller_valuator(ControllerConnection* c, int valuatorNum)
{
   unsigned char* pointer =
      reinterpret_cast<unsigned char*>(c->controller)
      + c->controller->valuatorOffset;
   float* valuators = reinterpret_cast<float*>(pointer);

   return valuators[valuatorNum];
}
<commit_msg>fix unix compile errors<commit_after>// Copied from public information at: http://www.evl.uic.edu/pape/CAVE/prog/
//
// Thanks Dave.
//
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <drivers/Open/Trackd/trackdmem.h>

#if !defined(VPR_OS_Windows)
#include <sys/ipc.h>
#include <sys/shm.h>
#endif

// ===========================================================================
// trackd tracker API

struct TrackerConnection
{
#if defined(VPR_OS_Windows)
   HANDLE                     file_mapping;
   CAVE_TRACKDTRACKER_HEADER* tracker;
#else
   int                        shmid;
   CAVE_TRACKDTRACKER_HEADER* tracker;
#endif
};

TrackerConnection*
trackd_tracker_attach(int shmKey)
{
   TrackerConnection* t = new TrackerConnection();

#if defined(VPR_OS_Windows)
   char shmfile[256];
   sprintf(shmfile, "%d", shmKey);
   t->file_mapping = OpenFileMapping(FILE_MAP_READ, FALSE, shmfile);

   if(!t->file_mapping)
   {
      fprintf(stderr, "ERROR: cannot get tracker shared memory\n");
      perror("OpenFileMapping");
      return NULL;
   }

   t->tracker =
      reinterpret_cast<CAVE_TRACKDTRACKER_HEADER*>(
         MapViewOfFile(t->file_mapping, FILE_MAP_READ, 0, 0, 0));

   if(!t->tracker)
   {
      fprintf(stderr, "ERROR: cannot attach tracker shared memory\n");
      perror("MapViewOfFile");
      return NULL;
   }
#else
   t->shmid = shmget(shmKey, sizeof(CAVE_TRACKDTRACKER_HEADER), 0);

   if(t->shmid < 0)
   {
      fprintf(stderr,"ERROR: can't get tracker shared memory\n");
      perror("shmget");
      return NULL;
   }

   t->tracker =
      reinterpret_cast<CAVE_TRACKDTRACKER_HEADER*>(
         shmat(t->shmid, (void *) 0, 0));

   if(t->tracker == reinterpret_cast<CAVE_TRACKDTRACKER_HEADER*>(-1))
   {
      fprintf(stderr,"ERROR: can't attach tracker shared memory\n");
      perror("shmat");
      return NULL;
   }
#endif

   return t;
}

void
trackd_tracker_release(TrackerConnection* t)
{
#if defined(VPR_OS_Windows)
   if(t && t->tracker)
   {
      UnmapViewOfFile(t->tracker);
      CloseHandle(t->file_mapping);
   }
#else
   if(t && t->tracker)
   {
#  ifdef __sun__
#     if defined(_XOPEN_SOURCE) && (_XOPEN_VERSION - 0 >= 4)
      shmdt(t->tracker);
#     else
      shmdt((char*) t->tracker);
#     endif
#  else
      shmdt(t->tracker);
#  endif
   }
#endif

   delete t;
}

int
trackd_tracker_num_sensors(TrackerConnection* t)
{
   return t->tracker->numSensors;
}

CAVE_SENSOR_ST*
trackd_tracker_sensor(TrackerConnection* t, int sensorNum)
{
   unsigned char* pointer =
      reinterpret_cast<unsigned char*>(t->tracker);

   pointer += t->tracker->sensorOffset + sensorNum * t->tracker->sensorSize;

   return reinterpret_cast<CAVE_SENSOR_ST*>(pointer);
}

// ===========================================================================
// trackd controller API

struct ControllerConnection
{
#if defined(VPR_OS_Windows)
   HANDLE                        file_mapping;
   CAVE_TRACKDCONTROLLER_HEADER* controller;
#else
   int                           shmid;
   CAVE_TRACKDCONTROLLER_HEADER* controller;
#endif
};

ControllerConnection*
trackd_controller_attach(int shmKey)
{
   ControllerConnection* c = new ControllerConnection();

#if defined(VPR_OS_Windows)
   char shmfile[256];
   sprintf(shmfile, "%d", shmKey);
   c->file_mapping = OpenFileMapping(FILE_MAP_READ, FALSE, shmfile);

   if(!c->file_mapping)
   {
      fprintf(stderr, "ERROR: cannot get controller shared memory\n");
      perror("OpenFileMapping");
      return NULL;
   }

   c->controller =
      reinterpret_cast<CAVE_TRACKDCONTROLLER_HEADER*>(
         MapViewOfFile(c->file_mapping, FILE_MAP_READ, 0, 0, 0));

   if(!c->controller)
   {
      fprintf(stderr, "ERROR: cannot attach controller shared memory\n");
      perror("MapViewOfFile");
      return NULL;
   }
#else
   c->shmid = shmget(shmKey, sizeof(CAVE_TRACKDCONTROLLER_HEADER), 0);

   if(c->shmid < 0)
   {
      fprintf(stderr,"ERROR: can't get controller shared memory\n");
      perror("shmget");
      return NULL;
   }

   c->controller =
      reinterpret_cast<CAVE_TRACKDCONTROLLER_HEADER*>(
         shmat(c->shmid, (void *) 0, 0));

   if(c->controller == (CAVE_TRACKDCONTROLLER_HEADER *) -1)
   {
      fprintf(stderr,"ERROR: can't attach controller shared memory\n");
      perror("shmat");
      return NULL;
   }
#endif

   return c;
}

void
trackd_controller_release(ControllerConnection* c)
{
#if defined(VPR_OS_Windows)
   if(c && c->controller)
   {
      UnmapViewOfFile(c->controller);
      CloseHandle(c->file_mapping);
   }
#else
   if(c && c->controller)
   {
#  ifdef __sun__
#     if defined(_XOPEN_SOURCE) && (_XOPEN_VERSION - 0 >= 4)
      shmdt(c->controller);
#     else
      shmdt((char*) c->controller);
#     endif
#  else
      shmdt(c->controller);
#  endif
   }
#endif

   delete c;
}

int
trackd_controller_num_buttons(ControllerConnection* c)
{
   return c->controller->numButtons;
}

int
trackd_controller_num_valuators(ControllerConnection* c)
{
   return c->controller->numValuators;
}

int
trackd_controller_button(ControllerConnection* c, int buttonNum)
{
   unsigned char* pointer =
      reinterpret_cast<unsigned char*>(c->controller)
      + c->controller->buttonOffset;
   int* buttons = reinterpret_cast<int*>(pointer);

   return buttons[buttonNum];
}

float
trackd_controller_valuator(ControllerConnection* c, int valuatorNum)
{
   unsigned char* pointer =
      reinterpret_cast<unsigned char*>(c->controller)
      + c->controller->valuatorOffset;
   float* valuators = reinterpret_cast<float*>(pointer);

   return valuators[valuatorNum];
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2009 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */
#ifndef __ARCH_ARM_MISCREGS_HH__
#define __ARCH_ARM_MISCREGS_HH__

#include "base/bitunion.hh"

namespace ArmISA
{
    enum ConditionCode {
        COND_EQ  =   0,
        COND_NE, //  1
        COND_CS, //  2
        COND_CC, //  3
        COND_MI, //  4
        COND_PL, //  5
        COND_VS, //  6
        COND_VC, //  7
        COND_HI, //  8
        COND_LS, //  9
        COND_GE, // 10
        COND_LT, // 11
        COND_GT, // 12
        COND_LE, // 13
        COND_AL, // 14
        COND_UC  // 15
    };

    enum MiscRegIndex {
        MISCREG_CPSR = 0,
        MISCREG_SPSR,
        MISCREG_SPSR_FIQ,
        MISCREG_SPSR_IRQ,
        MISCREG_SPSR_SVC,
        MISCREG_SPSR_MON,
        MISCREG_SPSR_UND,
        MISCREG_SPSR_ABT,
        MISCREG_FPSR,
        MISCREG_FPSID,
        MISCREG_FPSCR,
        MISCREG_FPEXC,
        MISCREG_MVFR0,
        MISCREG_MVFR1,
        MISCREG_SEV_MAILBOX,

        // CP15 registers
        MISCREG_CP15_START,
        MISCREG_SCTLR = MISCREG_CP15_START,
        MISCREG_DCCISW,
        MISCREG_DCCIMVAC,
        MISCREG_DCCMVAC,
        MISCREG_CONTEXTIDR,
        MISCREG_TPIDRURW,
        MISCREG_TPIDRURO,
        MISCREG_TPIDRPRW,
        MISCREG_CP15ISB,
        MISCREG_CP15DSB,
        MISCREG_CP15DMB,
        MISCREG_CPACR,
        MISCREG_CLIDR,
        MISCREG_CCSIDR,
        MISCREG_CSSELR,
        MISCREG_ICIALLUIS,
        MISCREG_ICIALLU,
        MISCREG_ICIMVAU,
        MISCREG_BPIMVA,
        MISCREG_BPIALLIS,
        MISCREG_BPIALL,
        MISCREG_MIDR,
        MISCREG_TTBR0,
        MISCREG_TTBR1,
        MISCREG_CP15_UNIMP_START,
        MISCREG_CTR = MISCREG_CP15_UNIMP_START,
        MISCREG_TLBTR,
        MISCREG_TCMTR,
        MISCREG_MPIDR,
        MISCREG_ID_PFR0,
        MISCREG_ID_PFR1,
        MISCREG_ID_DFR0,
        MISCREG_ID_AFR0,
        MISCREG_ID_MMFR0,
        MISCREG_ID_MMFR1,
        MISCREG_ID_MMFR2,
        MISCREG_ID_MMFR3,
        MISCREG_ID_ISAR0,
        MISCREG_ID_ISAR1,
        MISCREG_ID_ISAR2,
        MISCREG_ID_ISAR3,
        MISCREG_ID_ISAR4,
        MISCREG_ID_ISAR5,
        MISCREG_PAR,
        MISCREG_AIDR,
        MISCREG_ACTLR,
        MISCREG_DACR,
        MISCREG_DFSR,
        MISCREG_IFSR,
        MISCREG_ADFSR,
        MISCREG_AIFSR,
        MISCREG_DFAR,
        MISCREG_IFAR,
        MISCREG_DCIMVAC,
        MISCREG_DCISW,
        MISCREG_MCCSW,
        MISCREG_DCCMVAU,
        MISCREG_SCR,
        MISCREG_SDER,
        MISCREG_NSACR,
        MISCREG_TTBCR,
        MISCREG_V2PCWPR,
        MISCREG_V2PCWPW,
        MISCREG_V2PCWUR,
        MISCREG_V2PCWUW,
        MISCREG_V2POWPR,
        MISCREG_V2POWPW,
        MISCREG_V2POWUR,
        MISCREG_V2POWUW,
        MISCREG_TLBIALLIS,
        MISCREG_TLBIMVAIS,
        MISCREG_TLBIASIDIS,
        MISCREG_TLBIMVAAIS,
        MISCREG_ITLBIALL,
        MISCREG_ITLBIMVA,
        MISCREG_ITLBIASID,
        MISCREG_DTLBIALL,
        MISCREG_DTLBIMVA,
        MISCREG_DTLBIASID,
        MISCREG_TLBIALL,
        MISCREG_TLBIMVA,
        MISCREG_TLBIASID,
        MISCREG_TLBIMVAA,
        MISCREG_PRRR,
        MISCREG_NMRR,
        MISCREG_VBAR,
        MISCREG_MVBAR,
        MISCREG_ISR,
        MISCREG_FCEIDR,

        MISCREG_CP15_END,

        // Dummy indices
        MISCREG_NOP = MISCREG_CP15_END,
        MISCREG_RAZ,

        NUM_MISCREGS
    };

    MiscRegIndex decodeCP15Reg(unsigned crn, unsigned opc1,
                               unsigned crm, unsigned opc2);

    const char * const miscRegName[NUM_MISCREGS] = {
        "cpsr", "spsr", "spsr_fiq", "spsr_irq", "spsr_svc",
        "spsr_mon", "spsr_und", "spsr_abt",
        "fpsr", "fpsid", "fpscr", "fpexc", "mvfr0", "mvfr1",
        "sev_mailbox",
        "sctlr", "dccisw", "dccimvac", "dccmvac",
        "contextidr", "tpidrurw", "tpidruro", "tpidrprw",
        "cp15isb", "cp15dsb", "cp15dmb", "cpacr",
        "clidr", "ccsidr", "csselr",
        "icialluis", "iciallu", "icimvau",
        "bpimva", "bpiallis", "bpiall",
        "midr", "ttbr0", "ttbr1", "ctr", "tlbtr", "tcmtr", "mpidr",
        "id_pfr0", "id_pfr1", "id_dfr0", "id_afr0",
        "id_mmfr0", "id_mmfr1", "id_mmfr2", "id_mmfr3",
        "id_isar0", "id_isar1", "id_isar2", "id_isar3", "id_isar4", "id_isar5",
        "par", "aidr", "actlr", "dacr",
        "dfsr", "ifsr", "adfsr", "aifsr", "dfar", "ifar",
        "dcimvac", "dcisw", "mccsw",
        "dccmvau",
        "scr", "sder", "nsacr", "ttbcr",
        "v2pcwpr", "v2pcwpw", "v2pcwur", "v2pcwuw",
        "v2powpr", "v2powpw", "v2powur", "v2powuw",
        "tlbiallis", "tlbimvais", "tlbiasidis", "tlbimvaais",
        "itlbiall", "itlbimva", "itlbiasid",
        "dtlbiall", "dtlbimva", "dtlbiasid",
        "tlbiall", "tlbimva", "tlbiasid", "tlbimvaa",
        "prrr", "nmrr", "vbar", "mvbar", "isr", "fceidr",
        "nop", "raz"
    };

    BitUnion32(CPSR)
        Bitfield<31> n;
        Bitfield<30> z;
        Bitfield<29> c;
        Bitfield<28> v;
        Bitfield<27> q;
        Bitfield<26,25> it1;
        Bitfield<24> j;
        Bitfield<19, 16> ge;
        Bitfield<15,10> it2;
        Bitfield<9> e;
        Bitfield<8> a;
        Bitfield<7> i;
        Bitfield<6> f;
        Bitfield<5> t;
        Bitfield<4, 0> mode;
    EndBitUnion(CPSR)

    // This mask selects bits of the CPSR that actually go in the CondCodes
    // integer register to allow renaming.
    static const uint32_t CondCodesMask = 0xF80F0000;

    BitUnion32(SCTLR)
        Bitfield<30> te;  // Thumb Exception Enable
        Bitfield<29> afe; // Access flag enable
        Bitfield<28> tre; // TEX Remap bit
        Bitfield<27> nmfi;// Non-maskable fast interrupts enable
        Bitfield<25> ee;  // Exception Endianness bit
        Bitfield<24> ve;  // Interrupt vectors enable
        Bitfield<23> rao1;// Read as one
        Bitfield<22> u;   // Alignment (now unused)
        Bitfield<21> fi;  // Fast interrupts configuration enable
        Bitfield<18> rao2;// Read as one
        Bitfield<17> ha;  // Hardware access flag enable
        Bitfield<16> rao3;// Read as one
        Bitfield<14> rr;  // Round robin cache replacement
        Bitfield<13> v;   // Base address for exception vectors
        Bitfield<12> i;   // instruction cache enable
        Bitfield<11> z;   // branch prediction enable bit
        Bitfield<10> sw;  // Enable swp/swpb
        Bitfield<6,3> rao4;// Read as one
        Bitfield<7>  b;   // Endianness support (unused)
        Bitfield<2>  c;   // Cache enable bit
        Bitfield<1>  a;   // Alignment fault checking
        Bitfield<0>  m;   // MMU enable bit
    EndBitUnion(SCTLR)

    BitUnion32(CPACR)
        Bitfield<1, 0> cp0;
        Bitfield<3, 2> cp1;
        Bitfield<5, 4> cp2;
        Bitfield<7, 6> cp3;
        Bitfield<9, 8> cp4;
        Bitfield<11, 10> cp5;
        Bitfield<13, 12> cp6;
        Bitfield<15, 14> cp7;
        Bitfield<17, 16> cp8;
        Bitfield<19, 18> cp9;
        Bitfield<21, 20> cp10;
        Bitfield<23, 22> cp11;
        Bitfield<25, 24> cp12;
        Bitfield<27, 26> cp13;
        Bitfield<30> d32dis;
        Bitfield<31> asedis;
    EndBitUnion(CPACR)
};

#endif // __ARCH_ARM_MISCREGS_HH__
<commit_msg>ARM: Handle accesses to the DACR.<commit_after>/*
 * Copyright (c) 2010 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2009 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */
#ifndef __ARCH_ARM_MISCREGS_HH__
#define __ARCH_ARM_MISCREGS_HH__

#include "base/bitunion.hh"

namespace ArmISA
{
    enum ConditionCode {
        COND_EQ  =   0,
        COND_NE, //  1
        COND_CS, //  2
        COND_CC, //  3
        COND_MI, //  4
        COND_PL, //  5
        COND_VS, //  6
        COND_VC, //  7
        COND_HI, //  8
        COND_LS, //  9
        COND_GE, // 10
        COND_LT, // 11
        COND_GT, // 12
        COND_LE, // 13
        COND_AL, // 14
        COND_UC  // 15
    };

    enum MiscRegIndex {
        MISCREG_CPSR = 0,
        MISCREG_SPSR,
        MISCREG_SPSR_FIQ,
        MISCREG_SPSR_IRQ,
        MISCREG_SPSR_SVC,
        MISCREG_SPSR_MON,
        MISCREG_SPSR_UND,
        MISCREG_SPSR_ABT,
        MISCREG_FPSR,
        MISCREG_FPSID,
        MISCREG_FPSCR,
        MISCREG_FPEXC,
        MISCREG_MVFR0,
        MISCREG_MVFR1,
        MISCREG_SEV_MAILBOX,

        // CP15 registers
        MISCREG_CP15_START,
        MISCREG_SCTLR = MISCREG_CP15_START,
        MISCREG_DCCISW,
        MISCREG_DCCIMVAC,
        MISCREG_DCCMVAC,
        MISCREG_CONTEXTIDR,
        MISCREG_TPIDRURW,
        MISCREG_TPIDRURO,
        MISCREG_TPIDRPRW,
        MISCREG_CP15ISB,
        MISCREG_CP15DSB,
        MISCREG_CP15DMB,
        MISCREG_CPACR,
        MISCREG_CLIDR,
        MISCREG_CCSIDR,
        MISCREG_CSSELR,
        MISCREG_ICIALLUIS,
        MISCREG_ICIALLU,
        MISCREG_ICIMVAU,
        MISCREG_BPIMVA,
        MISCREG_BPIALLIS,
        MISCREG_BPIALL,
        MISCREG_MIDR,
        MISCREG_TTBR0,
        MISCREG_TTBR1,
        MISCREG_DACR,
        MISCREG_CP15_UNIMP_START,
        MISCREG_CTR = MISCREG_CP15_UNIMP_START,
        MISCREG_TLBTR,
        MISCREG_TCMTR,
        MISCREG_MPIDR,
        MISCREG_ID_PFR0,
        MISCREG_ID_PFR1,
        MISCREG_ID_DFR0,
        MISCREG_ID_AFR0,
        MISCREG_ID_MMFR0,
        MISCREG_ID_MMFR1,
        MISCREG_ID_MMFR2,
        MISCREG_ID_MMFR3,
        MISCREG_ID_ISAR0,
        MISCREG_ID_ISAR1,
        MISCREG_ID_ISAR2,
        MISCREG_ID_ISAR3,
        MISCREG_ID_ISAR4,
        MISCREG_ID_ISAR5,
        MISCREG_PAR,
        MISCREG_AIDR,
        MISCREG_ACTLR,
        MISCREG_DFSR,
        MISCREG_IFSR,
        MISCREG_ADFSR,
        MISCREG_AIFSR,
        MISCREG_DFAR,
        MISCREG_IFAR,
        MISCREG_DCIMVAC,
        MISCREG_DCISW,
        MISCREG_MCCSW,
        MISCREG_DCCMVAU,
        MISCREG_SCR,
        MISCREG_SDER,
        MISCREG_NSACR,
        MISCREG_TTBCR,
        MISCREG_V2PCWPR,
        MISCREG_V2PCWPW,
        MISCREG_V2PCWUR,
        MISCREG_V2PCWUW,
        MISCREG_V2POWPR,
        MISCREG_V2POWPW,
        MISCREG_V2POWUR,
        MISCREG_V2POWUW,
        MISCREG_TLBIALLIS,
        MISCREG_TLBIMVAIS,
        MISCREG_TLBIASIDIS,
        MISCREG_TLBIMVAAIS,
        MISCREG_ITLBIALL,
        MISCREG_ITLBIMVA,
        MISCREG_ITLBIASID,
        MISCREG_DTLBIALL,
        MISCREG_DTLBIMVA,
        MISCREG_DTLBIASID,
        MISCREG_TLBIALL,
        MISCREG_TLBIMVA,
        MISCREG_TLBIASID,
        MISCREG_TLBIMVAA,
        MISCREG_PRRR,
        MISCREG_NMRR,
        MISCREG_VBAR,
        MISCREG_MVBAR,
        MISCREG_ISR,
        MISCREG_FCEIDR,

        MISCREG_CP15_END,

        // Dummy indices
        MISCREG_NOP = MISCREG_CP15_END,
        MISCREG_RAZ,

        NUM_MISCREGS
    };

    MiscRegIndex decodeCP15Reg(unsigned crn, unsigned opc1,
                               unsigned crm, unsigned opc2);

    const char * const miscRegName[NUM_MISCREGS] = {
        "cpsr", "spsr", "spsr_fiq", "spsr_irq", "spsr_svc",
        "spsr_mon", "spsr_und", "spsr_abt",
        "fpsr", "fpsid", "fpscr", "fpexc", "mvfr0", "mvfr1",
        "sev_mailbox",
        "sctlr", "dccisw", "dccimvac", "dccmvac",
        "contextidr", "tpidrurw", "tpidruro", "tpidrprw",
        "cp15isb", "cp15dsb", "cp15dmb", "cpacr",
        "clidr", "ccsidr", "csselr",
        "icialluis", "iciallu", "icimvau",
        "bpimva", "bpiallis", "bpiall",
        "midr", "ttbr0", "ttbr1", "dacr", "ctr", "tlbtr", "tcmtr", "mpidr",
        "id_pfr0", "id_pfr1", "id_dfr0", "id_afr0",
        "id_mmfr0", "id_mmfr1", "id_mmfr2", "id_mmfr3",
        "id_isar0", "id_isar1", "id_isar2", "id_isar3", "id_isar4", "id_isar5",
        "par", "aidr", "actlr",
        "dfsr", "ifsr", "adfsr", "aifsr", "dfar", "ifar",
        "dcimvac", "dcisw", "mccsw",
        "dccmvau",
        "scr", "sder", "nsacr", "ttbcr",
        "v2pcwpr", "v2pcwpw", "v2pcwur", "v2pcwuw",
        "v2powpr", "v2powpw", "v2powur", "v2powuw",
        "tlbiallis", "tlbimvais", "tlbiasidis", "tlbimvaais",
        "itlbiall", "itlbimva", "itlbiasid",
        "dtlbiall", "dtlbimva", "dtlbiasid",
        "tlbiall", "tlbimva", "tlbiasid", "tlbimvaa",
        "prrr", "nmrr", "vbar", "mvbar", "isr", "fceidr",
        "nop", "raz"
    };

    BitUnion32(CPSR)
        Bitfield<31> n;
        Bitfield<30> z;
        Bitfield<29> c;
        Bitfield<28> v;
        Bitfield<27> q;
        Bitfield<26,25> it1;
        Bitfield<24> j;
        Bitfield<19, 16> ge;
        Bitfield<15,10> it2;
        Bitfield<9> e;
        Bitfield<8> a;
        Bitfield<7> i;
        Bitfield<6> f;
        Bitfield<5> t;
        Bitfield<4, 0> mode;
    EndBitUnion(CPSR)

    // This mask selects bits of the CPSR that actually go in the CondCodes
    // integer register to allow renaming.
    static const uint32_t CondCodesMask = 0xF80F0000;

    BitUnion32(SCTLR)
        Bitfield<30> te;  // Thumb Exception Enable
        Bitfield<29> afe; // Access flag enable
        Bitfield<28> tre; // TEX Remap bit
        Bitfield<27> nmfi;// Non-maskable fast interrupts enable
        Bitfield<25> ee;  // Exception Endianness bit
        Bitfield<24> ve;  // Interrupt vectors enable
        Bitfield<23> rao1;// Read as one
        Bitfield<22> u;   // Alignment (now unused)
        Bitfield<21> fi;  // Fast interrupts configuration enable
        Bitfield<18> rao2;// Read as one
        Bitfield<17> ha;  // Hardware access flag enable
        Bitfield<16> rao3;// Read as one
        Bitfield<14> rr;  // Round robin cache replacement
        Bitfield<13> v;   // Base address for exception vectors
        Bitfield<12> i;   // instruction cache enable
        Bitfield<11> z;   // branch prediction enable bit
        Bitfield<10> sw;  // Enable swp/swpb
        Bitfield<6,3> rao4;// Read as one
        Bitfield<7>  b;   // Endianness support (unused)
        Bitfield<2>  c;   // Cache enable bit
        Bitfield<1>  a;   // Alignment fault checking
        Bitfield<0>  m;   // MMU enable bit
    EndBitUnion(SCTLR)

    BitUnion32(CPACR)
        Bitfield<1, 0> cp0;
        Bitfield<3, 2> cp1;
        Bitfield<5, 4> cp2;
        Bitfield<7, 6> cp3;
        Bitfield<9, 8> cp4;
        Bitfield<11, 10> cp5;
        Bitfield<13, 12> cp6;
        Bitfield<15, 14> cp7;
        Bitfield<17, 16> cp8;
        Bitfield<19, 18> cp9;
        Bitfield<21, 20> cp10;
        Bitfield<23, 22> cp11;
        Bitfield<25, 24> cp12;
        Bitfield<27, 26> cp13;
        Bitfield<30> d32dis;
        Bitfield<31> asedis;
    EndBitUnion(CPACR)
};

#endif // __ARCH_ARM_MISCREGS_HH__
<|endoftext|>


<commit_before>//===--- Linker.cpp -------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// The SIL linker walks the call graph beginning at a starting function,
/// deserializing functions, vtables and witness tables.
///
/// The behavior of the linker is controlled by a LinkMode value. The LinkMode
/// has three possible values:
///
/// - LinkNone: The linker does not deserialize anything. This is only used for
///   debugging and testing purposes, and never during normal operation.
///
/// - LinkNormal: The linker deserializes bodies for declarations that must be
///   emitted into the client because they do not have definitions available
///   externally. This includes:
///
///   - witness tables for imported conformances
///
///   - functions with shared linkage
///
/// - LinkAll: All reachable functions (including public functions) are
///   deserialized, including public functions.
///
/// The primary entry point into the linker is the SILModule::linkFunction()
/// function, which recursively walks the call graph starting from the given
/// function.
///
/// In the mandatory pipeline (-Onone), the linker is invoked from the mandatory
/// SIL linker pass, which pulls in just enough to allow us to emit code, using
/// LinkNormal mode.
///
/// In the performance pipeline, after guaranteed optimizations but before
/// performance optimizations, the 'performance SILLinker' pass links
/// transitively all reachable functions, to uncover optimization opportunities
/// that might be missed from deserializing late. The performance pipeline uses
/// LinkAll mode.
///
/// *NOTE*: In LinkAll mode, we deserialize all vtables and witness tables,
/// even those with public linkage. This is not strictly necessary, since the
/// devirtualizer deserializes vtables and witness tables as needed. However,
/// doing so early creates more opportunities for optimization.
///
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-linker"
#include "Linker.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/SIL/FormalLinkage.h"
#include <functional>

using namespace swift;
using namespace Lowering;

STATISTIC(NumFuncLinked, "Number of SIL functions linked");

//===----------------------------------------------------------------------===//
//                               Linker Helpers
//===----------------------------------------------------------------------===//

void SILLinkerVisitor::addFunctionToWorklist(SILFunction *F) {
  assert(F->isExternalDeclaration());

  LLVM_DEBUG(llvm::dbgs() << "Imported function: "
                          << F->getName() << "\n");
  if (Mod.loadFunction(F)) {
    if (F->isExternalDeclaration())
      return;

    F->setBare(IsBare);
    F->verify();
    Worklist.push_back(F);
    Changed = true;
    ++NumFuncLinked;
  }
}

/// Deserialize a function and add it to the worklist for processing.
void SILLinkerVisitor::maybeAddFunctionToWorklist(SILFunction *F) {
  // Don't need to do anything if the function already has a body.
  if (!F->isExternalDeclaration())
    return;

  // In the performance pipeline, we deserialize all reachable functions.
  if (isLinkAll())
    return addFunctionToWorklist(F);

  // Otherwise, make sure to deserialize shared functions; we need to
  // emit them into the client binary since they're not available
  // externally.
  if (hasSharedVisibility(F->getLinkage()))
    return addFunctionToWorklist(F);

  // Functions with PublicNonABI linkage are deserialized as having
  // HiddenExternal linkage when they are declarations, then they
  // become SharedExternal after the body has been deserialized.
  // So try deserializing HiddenExternal functions too.
  if (F->getLinkage() == SILLinkage::HiddenExternal)
    return addFunctionToWorklist(F);
}

/// Process F, recursively deserializing any thing F may reference.
bool SILLinkerVisitor::processFunction(SILFunction *F) {
  // If F is a declaration, first deserialize it.
  if (F->isExternalDeclaration()) {
    maybeAddFunctionToWorklist(F);
  } else {
    Worklist.push_back(F);
  }

  process();
  return Changed;
}

/// Deserialize the given VTable all SIL the VTable transitively references.
void SILLinkerVisitor::linkInVTable(ClassDecl *D) {
  // Devirtualization already deserializes vtables as needed in both the
  // mandatory and performance pipelines, and we don't support specialized
  // vtables that might have shared linkage yet, so this is only needed in
  // the performance pipeline to deserialize more functions early, and expose
  // optimization opportunities.
  assert(isLinkAll());

  // Attempt to lookup the Vtbl from the SILModule.
  SILVTable *Vtbl = Mod.lookUpVTable(D);
  if (!Vtbl)
    return;

  // Ok we found our VTable. Visit each function referenced by the VTable. If
  // any of the functions are external declarations, add them to the worklist
  // for processing.
  for (auto P : Vtbl->getEntries()) {
    // Deserialize and recursively walk any vtable entries that do not have
    // bodies yet.
    maybeAddFunctionToWorklist(P.Implementation);
  }
}

//===----------------------------------------------------------------------===//
//                                  Visitors
//===----------------------------------------------------------------------===//

void SILLinkerVisitor::visitApplyInst(ApplyInst *AI) {
  visitApplySubstitutions(AI->getSubstitutionMap());
}

void SILLinkerVisitor::visitTryApplyInst(TryApplyInst *TAI) {
  visitApplySubstitutions(TAI->getSubstitutionMap());
}

void SILLinkerVisitor::visitPartialApplyInst(PartialApplyInst *PAI) {
  visitApplySubstitutions(PAI->getSubstitutionMap());
}

void SILLinkerVisitor::visitFunctionRefInst(FunctionRefInst *FRI) {
  maybeAddFunctionToWorklist(FRI->getReferencedFunction());
}

void SILLinkerVisitor::visitDynamicFunctionRefInst(
    DynamicFunctionRefInst *FRI) {
  maybeAddFunctionToWorklist(FRI->getReferencedFunction());
}

void SILLinkerVisitor::visitPreviousDynamicFunctionRefInst(
    PreviousDynamicFunctionRefInst *FRI) {
  maybeAddFunctionToWorklist(FRI->getReferencedFunction());
}

// Eagerly visiting all used conformances leads to a large blowup
// in the amount of SIL we read in. For optimization purposes we can defer
// reading in most conformances until we need them for devirtualization.
// However, we *must* pull in shared clang-importer-derived conformances
// we potentially use, since we may not otherwise have a local definition.
static bool mustDeserializeProtocolConformance(SILModule &M,
                                               ProtocolConformanceRef c) {
  if (!c.isConcrete())
    return false;
  auto conformance = c.getConcrete()->getRootNormalConformance();
  return M.Types.protocolRequiresWitnessTable(conformance->getProtocol())
    && isa<ClangModuleUnit>(conformance->getDeclContext()
                                       ->getModuleScopeContext());
}

void SILLinkerVisitor::visitProtocolConformance(
    ProtocolConformanceRef ref, const Optional<SILDeclRef> &Member) {
  // If an abstract protocol conformance was passed in, just return false.
  if (ref.isAbstract())
    return;

  bool mustDeserialize = mustDeserializeProtocolConformance(Mod, ref);

  // Otherwise try and lookup a witness table for C.
  auto C = ref.getConcrete();

  if (!VisitedConformances.insert(C).second)
    return;

  SILWitnessTable *WT = Mod.lookUpWitnessTable(C, /*deserializeLazily=*/false);

  // If we don't find any witness table for the conformance, bail and return
  // false.
  if (!WT) {
    Mod.createWitnessTableDeclaration(C);

    // Adding the declaration may allow us to now deserialize the body.
    // Force the body if we must deserialize this witness table.
    if (mustDeserialize) {
      WT = Mod.lookUpWitnessTable(C, /*deserializeLazily=*/true);
      assert(WT && WT->isDefinition()
             && "unable to deserialize witness table when we must?!");
    } else {
      return;
    }
  }

  // If the looked up witness table is a declaration, there is nothing we can
  // do here. Just bail and return false.
  if (WT->isDeclaration())
    return;

  auto maybeVisitRelatedConformance = [&](ProtocolConformanceRef c) {
    // Formally all conformances referenced by a used conformance are used.
    // However, eagerly visiting them all at this point leads to a large blowup
    // in the amount of SIL we read in. For optimization purposes we can defer
    // reading in most conformances until we need them for devirtualization.
    // However, we *must* pull in shared clang-importer-derived conformances
    // we potentially use, since we may not otherwise have a local definition.
    if (mustDeserializeProtocolConformance(Mod, c))
      visitProtocolConformance(c, None);
  };

  // For each entry in the witness table...
  for (auto &E : WT->getEntries()) {
    switch (E.getKind()) {
    // If the entry is a witness method...
    case SILWitnessTable::WitnessKind::Method: {
      // And we are only interested in deserializing a specific requirement
      // and don't have that requirement, don't deserialize this method.
      if (Member.hasValue() && E.getMethodWitness().Requirement != *Member)
        continue;

      // The witness could be removed by dead function elimination.
      if (!E.getMethodWitness().Witness)
        continue;

      // Otherwise, deserialize the witness if it has shared linkage, or if
      // we were asked to deserialize everything.
      maybeAddFunctionToWorklist(E.getMethodWitness().Witness);
      break;
    }

    // If the entry is a related witness table, see whether we need to
    // eagerly deserialize it.
    case SILWitnessTable::WitnessKind::BaseProtocol: {
      auto baseConformance = E.getBaseProtocolWitness().Witness;
      maybeVisitRelatedConformance(ProtocolConformanceRef(baseConformance));
      break;
    }
    case SILWitnessTable::WitnessKind::AssociatedTypeProtocol: {
      auto assocConformance = E.getAssociatedTypeProtocolWitness().Witness;
      maybeVisitRelatedConformance(assocConformance);
      break;
    }

    case SILWitnessTable::WitnessKind::AssociatedType:
    case SILWitnessTable::WitnessKind::Invalid:
      break;
    }
  }
}

void SILLinkerVisitor::visitApplySubstitutions(SubstitutionMap subs) {
  for (auto conformance : subs.getConformances()) {
    // Formally all conformances referenced in a function application are
    // used. However, eagerly visiting them all at this point leads to a
    // large blowup in the amount of SIL we read in, and we aren't very
    // systematic about laziness. For optimization purposes we can defer
    // reading in most conformances until we need them for devirtualization.
    // However, we *must* pull in shared clang-importer-derived conformances
    // we potentially use, since we may not otherwise have a local definition.
    if (mustDeserializeProtocolConformance(Mod, conformance)) {
      visitProtocolConformance(conformance, None);
    }
  }
}

void SILLinkerVisitor::visitInitExistentialAddrInst(
    InitExistentialAddrInst *IEI) {
  // Link in all protocol conformances that this touches.
  //
  // TODO: There might be a two step solution where the init_existential_inst
  // causes the witness table to be brought in as a declaration and then the
  // protocol method inst causes the actual deserialization. For now we are
  // not going to be smart about this to enable avoiding any issues with
  // visiting the open_existential_addr/witness_method before the
  // init_existential_inst.
  for (ProtocolConformanceRef C : IEI->getConformances()) {
    visitProtocolConformance(C, Optional<SILDeclRef>());
  }
}

void SILLinkerVisitor::visitInitExistentialRefInst(
    InitExistentialRefInst *IERI) {
  // Link in all protocol conformances that this touches.
  //
  // TODO: There might be a two step solution where the init_existential_inst
  // causes the witness table to be brought in as a declaration and then the
  // protocol method inst causes the actual deserialization. For now we are
  // not going to be smart about this to enable avoiding any issues with
  // visiting the protocol_method before the init_existential_inst.
  for (ProtocolConformanceRef C : IERI->getConformances()) {
    visitProtocolConformance(C, Optional<SILDeclRef>());
  }
}

void SILLinkerVisitor::visitAllocRefInst(AllocRefInst *ARI) {
  if (!isLinkAll())
    return;

  // Grab the class decl from the alloc ref inst.
  ClassDecl *D = ARI->getType().getClassOrBoundGenericClass();
  if (!D)
    return;

  linkInVTable(D);
}

void SILLinkerVisitor::visitMetatypeInst(MetatypeInst *MI) {
  if (!isLinkAll())
    return;

  CanType instTy = MI->getType().castTo<MetatypeType>().getInstanceType();
  ClassDecl *C = instTy.getClassOrBoundGenericClass();
  if (!C)
    return;

  linkInVTable(C);
}

//===----------------------------------------------------------------------===//
//                             Top Level Routine
//===----------------------------------------------------------------------===//

// Main loop of the visitor. Called by one of the other *visit* methods.
void SILLinkerVisitor::process() {
  // Process everything transitively referenced by one of the functions in the
  // worklist.
  while (!Worklist.empty()) {
    auto *Fn = Worklist.pop_back_val();

    if (Fn->getModule().isSerialized()) {
      // If the containing module has been serialized,
      // Remove The Serialized state (if any)
      //  This allows for more optimizations
      Fn->setSerialized(IsSerialized_t::IsNotSerialized);
    }

    LLVM_DEBUG(llvm::dbgs() << "Process imports in function: "
                            << Fn->getName() << "\n");

    for (auto &BB : *Fn) {
      for (auto &I : BB) {
        visit(&I);
      }
    }
  }
}
<commit_msg>SIL: Simplify SILLinkerVisitor::visitProtocolConformance()<commit_after>//===--- Linker.cpp -------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// The SIL linker walks the call graph beginning at a starting function,
/// deserializing functions, vtables and witness tables.
///
/// The behavior of the linker is controlled by a LinkMode value. The LinkMode
/// has three possible values:
///
/// - LinkNone: The linker does not deserialize anything. This is only used for
///   debugging and testing purposes, and never during normal operation.
///
/// - LinkNormal: The linker deserializes bodies for declarations that must be
///   emitted into the client because they do not have definitions available
///   externally. This includes:
///
///   - witness tables for imported conformances
///
///   - functions with shared linkage
///
/// - LinkAll: All reachable functions (including public functions) are
///   deserialized, including public functions.
///
/// The primary entry point into the linker is the SILModule::linkFunction()
/// function, which recursively walks the call graph starting from the given
/// function.
///
/// In the mandatory pipeline (-Onone), the linker is invoked from the mandatory
/// SIL linker pass, which pulls in just enough to allow us to emit code, using
/// LinkNormal mode.
///
/// In the performance pipeline, after guaranteed optimizations but before
/// performance optimizations, the 'performance SILLinker' pass links
/// transitively all reachable functions, to uncover optimization opportunities
/// that might be missed from deserializing late. The performance pipeline uses
/// LinkAll mode.
///
/// *NOTE*: In LinkAll mode, we deserialize all vtables and witness tables,
/// even those with public linkage. This is not strictly necessary, since the
/// devirtualizer deserializes vtables and witness tables as needed. However,
/// doing so early creates more opportunities for optimization.
///
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-linker"
#include "Linker.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/SIL/FormalLinkage.h"
#include <functional>

using namespace swift;
using namespace Lowering;

STATISTIC(NumFuncLinked, "Number of SIL functions linked");

//===----------------------------------------------------------------------===//
//                               Linker Helpers
//===----------------------------------------------------------------------===//

void SILLinkerVisitor::addFunctionToWorklist(SILFunction *F) {
  assert(F->isExternalDeclaration());

  LLVM_DEBUG(llvm::dbgs() << "Imported function: "
                          << F->getName() << "\n");
  if (Mod.loadFunction(F)) {
    if (F->isExternalDeclaration())
      return;

    F->setBare(IsBare);
    F->verify();
    Worklist.push_back(F);
    Changed = true;
    ++NumFuncLinked;
  }
}

/// Deserialize a function and add it to the worklist for processing.
void SILLinkerVisitor::maybeAddFunctionToWorklist(SILFunction *F) {
  // Don't need to do anything if the function already has a body.
  if (!F->isExternalDeclaration())
    return;

  // In the performance pipeline, we deserialize all reachable functions.
  if (isLinkAll())
    return addFunctionToWorklist(F);

  // Otherwise, make sure to deserialize shared functions; we need to
  // emit them into the client binary since they're not available
  // externally.
  if (hasSharedVisibility(F->getLinkage()))
    return addFunctionToWorklist(F);

  // Functions with PublicNonABI linkage are deserialized as having
  // HiddenExternal linkage when they are declarations, then they
  // become SharedExternal after the body has been deserialized.
  // So try deserializing HiddenExternal functions too.
  if (F->getLinkage() == SILLinkage::HiddenExternal)
    return addFunctionToWorklist(F);
}

/// Process F, recursively deserializing any thing F may reference.
bool SILLinkerVisitor::processFunction(SILFunction *F) {
  // If F is a declaration, first deserialize it.
  if (F->isExternalDeclaration()) {
    maybeAddFunctionToWorklist(F);
  } else {
    Worklist.push_back(F);
  }

  process();
  return Changed;
}

/// Deserialize the given VTable all SIL the VTable transitively references.
void SILLinkerVisitor::linkInVTable(ClassDecl *D) {
  // Devirtualization already deserializes vtables as needed in both the
  // mandatory and performance pipelines, and we don't support specialized
  // vtables that might have shared linkage yet, so this is only needed in
  // the performance pipeline to deserialize more functions early, and expose
  // optimization opportunities.
  assert(isLinkAll());

  // Attempt to lookup the Vtbl from the SILModule.
  SILVTable *Vtbl = Mod.lookUpVTable(D);
  if (!Vtbl)
    return;

  // Ok we found our VTable. Visit each function referenced by the VTable. If
  // any of the functions are external declarations, add them to the worklist
  // for processing.
  for (auto P : Vtbl->getEntries()) {
    // Deserialize and recursively walk any vtable entries that do not have
    // bodies yet.
    maybeAddFunctionToWorklist(P.Implementation);
  }
}

//===----------------------------------------------------------------------===//
//                                  Visitors
//===----------------------------------------------------------------------===//

void SILLinkerVisitor::visitApplyInst(ApplyInst *AI) {
  visitApplySubstitutions(AI->getSubstitutionMap());
}

void SILLinkerVisitor::visitTryApplyInst(TryApplyInst *TAI) {
  visitApplySubstitutions(TAI->getSubstitutionMap());
}

void SILLinkerVisitor::visitPartialApplyInst(PartialApplyInst *PAI) {
  visitApplySubstitutions(PAI->getSubstitutionMap());
}

void SILLinkerVisitor::visitFunctionRefInst(FunctionRefInst *FRI) {
  maybeAddFunctionToWorklist(FRI->getReferencedFunction());
}

void SILLinkerVisitor::visitDynamicFunctionRefInst(
    DynamicFunctionRefInst *FRI) {
  maybeAddFunctionToWorklist(FRI->getReferencedFunction());
}

void SILLinkerVisitor::visitPreviousDynamicFunctionRefInst(
    PreviousDynamicFunctionRefInst *FRI) {
  maybeAddFunctionToWorklist(FRI->getReferencedFunction());
}

// Eagerly visiting all used conformances leads to a large blowup
// in the amount of SIL we read in. For optimization purposes we can defer
// reading in most conformances until we need them for devirtualization.
// However, we *must* pull in shared clang-importer-derived conformances
// we potentially use, since we may not otherwise have a local definition.
static bool mustDeserializeProtocolConformance(SILModule &M,
                                               ProtocolConformanceRef c) {
  if (!c.isConcrete())
    return false;
  auto conformance = c.getConcrete()->getRootNormalConformance();
  return M.Types.protocolRequiresWitnessTable(conformance->getProtocol())
    && isa<ClangModuleUnit>(conformance->getDeclContext()
                                       ->getModuleScopeContext());
}

void SILLinkerVisitor::visitProtocolConformance(
    ProtocolConformanceRef ref, const Optional<SILDeclRef> &Member) {
  // If an abstract protocol conformance was passed in, do nothing.
  if (ref.isAbstract())
    return;

  bool mustDeserialize = mustDeserializeProtocolConformance(Mod, ref);

  // Otherwise try and lookup a witness table for C.
  auto C = ref.getConcrete();

  if (!VisitedConformances.insert(C).second)
    return;

  auto *WT = Mod.lookUpWitnessTable(C, mustDeserialize);

  // If the looked up witness table is a declaration, there is nothing we can
  // do here.
  if (WT == nullptr || WT->isDeclaration()) {
    assert(!mustDeserialize &&
           "unable to deserialize witness table when we must?!");
    return;
  }

  auto maybeVisitRelatedConformance = [&](ProtocolConformanceRef c) {
    // Formally all conformances referenced by a used conformance are used.
    // However, eagerly visiting them all at this point leads to a large blowup
    // in the amount of SIL we read in. For optimization purposes we can defer
    // reading in most conformances until we need them for devirtualization.
    // However, we *must* pull in shared clang-importer-derived conformances
    // we potentially use, since we may not otherwise have a local definition.
    if (mustDeserializeProtocolConformance(Mod, c))
      visitProtocolConformance(c, None);
  };

  // For each entry in the witness table...
  for (auto &E : WT->getEntries()) {
    switch (E.getKind()) {
    // If the entry is a witness method...
    case SILWitnessTable::WitnessKind::Method: {
      // And we are only interested in deserializing a specific requirement
      // and don't have that requirement, don't deserialize this method.
      if (Member.hasValue() && E.getMethodWitness().Requirement != *Member)
        continue;

      // The witness could be removed by dead function elimination.
      if (!E.getMethodWitness().Witness)
        continue;

      // Otherwise, deserialize the witness if it has shared linkage, or if
      // we were asked to deserialize everything.
      maybeAddFunctionToWorklist(E.getMethodWitness().Witness);
      break;
    }

    // If the entry is a related witness table, see whether we need to
    // eagerly deserialize it.
    case SILWitnessTable::WitnessKind::BaseProtocol: {
      auto baseConformance = E.getBaseProtocolWitness().Witness;
      maybeVisitRelatedConformance(ProtocolConformanceRef(baseConformance));
      break;
    }
    case SILWitnessTable::WitnessKind::AssociatedTypeProtocol: {
      auto assocConformance = E.getAssociatedTypeProtocolWitness().Witness;
      maybeVisitRelatedConformance(assocConformance);
      break;
    }

    case SILWitnessTable::WitnessKind::AssociatedType:
    case SILWitnessTable::WitnessKind::Invalid:
      break;
    }
  }
}

void SILLinkerVisitor::visitApplySubstitutions(SubstitutionMap subs) {
  for (auto conformance : subs.getConformances()) {
    // Formally all conformances referenced in a function application are
    // used. However, eagerly visiting them all at this point leads to a
    // large blowup in the amount of SIL we read in, and we aren't very
    // systematic about laziness. For optimization purposes we can defer
    // reading in most conformances until we need them for devirtualization.
    // However, we *must* pull in shared clang-importer-derived conformances
    // we potentially use, since we may not otherwise have a local definition.
    if (mustDeserializeProtocolConformance(Mod, conformance)) {
      visitProtocolConformance(conformance, None);
    }
  }
}

void SILLinkerVisitor::visitInitExistentialAddrInst(
    InitExistentialAddrInst *IEI) {
  // Link in all protocol conformances that this touches.
  //
  // TODO: There might be a two step solution where the init_existential_inst
  // causes the witness table to be brought in as a declaration and then the
  // protocol method inst causes the actual deserialization. For now we are
  // not going to be smart about this to enable avoiding any issues with
  // visiting the open_existential_addr/witness_method before the
  // init_existential_inst.
  for (ProtocolConformanceRef C : IEI->getConformances()) {
    visitProtocolConformance(C, Optional<SILDeclRef>());
  }
}

void SILLinkerVisitor::visitInitExistentialRefInst(
    InitExistentialRefInst *IERI) {
  // Link in all protocol conformances that this touches.
  //
  // TODO: There might be a two step solution where the init_existential_inst
  // causes the witness table to be brought in as a declaration and then the
  // protocol method inst causes the actual deserialization. For now we are
  // not going to be smart about this to enable avoiding any issues with
  // visiting the protocol_method before the init_existential_inst.
  for (ProtocolConformanceRef C : IERI->getConformances()) {
    visitProtocolConformance(C, Optional<SILDeclRef>());
  }
}

void SILLinkerVisitor::visitAllocRefInst(AllocRefInst *ARI) {
  if (!isLinkAll())
    return;

  // Grab the class decl from the alloc ref inst.
  ClassDecl *D = ARI->getType().getClassOrBoundGenericClass();
  if (!D)
    return;

  linkInVTable(D);
}

void SILLinkerVisitor::visitMetatypeInst(MetatypeInst *MI) {
  if (!isLinkAll())
    return;

  CanType instTy = MI->getType().castTo<MetatypeType>().getInstanceType();
  ClassDecl *C = instTy.getClassOrBoundGenericClass();
  if (!C)
    return;

  linkInVTable(C);
}

//===----------------------------------------------------------------------===//
//                             Top Level Routine
//===----------------------------------------------------------------------===//

// Main loop of the visitor. Called by one of the other *visit* methods.
void SILLinkerVisitor::process() {
  // Process everything transitively referenced by one of the functions in the
  // worklist.
  while (!Worklist.empty()) {
    auto *Fn = Worklist.pop_back_val();

    if (Fn->getModule().isSerialized()) {
      // If the containing module has been serialized,
      // Remove The Serialized state (if any)
      //  This allows for more optimizations
      Fn->setSerialized(IsSerialized_t::IsNotSerialized);
    }

    LLVM_DEBUG(llvm::dbgs() << "Process imports in function: "
                            << Fn->getName() << "\n");

    for (auto &BB : *Fn) {
      for (auto &I : BB) {
        visit(&I);
      }
    }
  }
}
<|endoftext|>