/ disassembler / Disassembler.cpp
Disassembler.cpp
  1  /*
  2   * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without
  5   * modification, are permitted provided that the following conditions
  6   * are met:
  7   * 1. Redistributions of source code must retain the above copyright
  8   *    notice, this list of conditions and the following disclaimer.
  9   * 2. Redistributions in binary form must reproduce the above copyright
 10   *    notice, this list of conditions and the following disclaimer in the
 11   *    documentation and/or other materials provided with the distribution.
 12   *
 13   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 17   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 24   */
 25  
 26  #include "config.h"
 27  #include "Disassembler.h"
 28  
 29  #include "MacroAssemblerCodeRef.h"
 30  #include <wtf/Condition.h>
 31  #include <wtf/DataLog.h>
 32  #include <wtf/Deque.h>
 33  #include <wtf/Lock.h>
 34  #include <wtf/NeverDestroyed.h>
 35  #include <wtf/Threading.h>
 36  
 37  namespace JSC {
 38  
 39  void disassemble(const MacroAssemblerCodePtr<DisassemblyPtrTag>& codePtr, size_t size, const char* prefix, PrintStream& out)
 40  {
 41      if (tryToDisassemble(codePtr, size, prefix, out))
 42          return;
 43      
 44      out.printf("%sdisassembly not available for range %p...%p\n", prefix, codePtr.untaggedExecutableAddress(), codePtr.untaggedExecutableAddress<char*>() + size);
 45  }
 46  
 47  namespace {
 48  
 49  // This is really a struct, except that it should be a class because that's what the WTF_* macros
 50  // expect.
 51  class DisassemblyTask {
 52      WTF_MAKE_NONCOPYABLE(DisassemblyTask);
 53      WTF_MAKE_FAST_ALLOCATED;
 54  public:
 55      DisassemblyTask()
 56      {
 57      }
 58      
 59      ~DisassemblyTask()
 60      {
 61          if (header)
 62              free(header); // free() because it would have been copied by strdup.
 63      }
 64      
 65      char* header { nullptr };
 66      MacroAssemblerCodeRef<DisassemblyPtrTag> codeRef;
 67      size_t size { 0 };
 68      const char* prefix { nullptr };
 69  };
 70  
 71  class AsynchronousDisassembler {
 72  public:
 73      AsynchronousDisassembler()
 74      {
 75          Thread::create("Asynchronous Disassembler", [&] () { run(); });
 76      }
 77      
 78      void enqueue(std::unique_ptr<DisassemblyTask> task)
 79      {
 80          LockHolder locker(m_lock);
 81          m_queue.append(WTFMove(task));
 82          m_condition.notifyAll();
 83      }
 84      
 85      void waitUntilEmpty()
 86      {
 87          LockHolder locker(m_lock);
 88          while (!m_queue.isEmpty() || m_working)
 89              m_condition.wait(m_lock);
 90      }
 91      
 92  private:
 93      NO_RETURN void run()
 94      {
 95          for (;;) {
 96              std::unique_ptr<DisassemblyTask> task;
 97              {
 98                  LockHolder locker(m_lock);
 99                  m_working = false;
100                  m_condition.notifyAll();
101                  while (m_queue.isEmpty())
102                      m_condition.wait(m_lock);
103                  task = m_queue.takeFirst();
104                  m_working = true;
105              }
106  
107              dataLog(task->header);
108              disassemble(task->codeRef.code(), task->size, task->prefix, WTF::dataFile());
109          }
110      }
111      
112      Lock m_lock;
113      Condition m_condition;
114      Deque<std::unique_ptr<DisassemblyTask>> m_queue;
115      bool m_working { false };
116  };
117  
118  bool hadAnyAsynchronousDisassembly = false;
119  
120  AsynchronousDisassembler& asynchronousDisassembler()
121  {
122      static LazyNeverDestroyed<AsynchronousDisassembler> disassembler;
123      static std::once_flag onceKey;
124      std::call_once(onceKey, [&] {
125          disassembler.construct();
126          hadAnyAsynchronousDisassembly = true;
127      });
128      return disassembler.get();
129  }
130  
131  } // anonymous namespace
132  
133  void disassembleAsynchronously(
134      const CString& header, const MacroAssemblerCodeRef<DisassemblyPtrTag>& codeRef, size_t size, const char* prefix)
135  {
136      std::unique_ptr<DisassemblyTask> task = makeUnique<DisassemblyTask>();
137      task->header = strdup(header.data()); // Yuck! We need this because CString does racy refcounting.
138      task->codeRef = codeRef;
139      task->size = size;
140      task->prefix = prefix;
141      
142      asynchronousDisassembler().enqueue(WTFMove(task));
143  }
144  
145  void waitForAsynchronousDisassembly()
146  {
147      if (!hadAnyAsynchronousDisassembly)
148          return;
149      
150      asynchronousDisassembler().waitUntilEmpty();
151  }
152  
153  } // namespace JSC
154