1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_DIAGNOSTICS_CODE_TRACER_H_
6 #define V8_DIAGNOSTICS_CODE_TRACER_H_
7 
8 #include "src/base/optional.h"
9 #include "src/base/platform/wrappers.h"
10 #include "src/base/strings.h"
11 #include "src/base/vector.h"
12 #include "src/common/globals.h"
13 #include "src/flags/flags.h"
14 #include "src/utils/allocation.h"
15 #include "src/utils/ostreams.h"
16 #include "src/utils/utils.h"
17 
18 namespace v8 {
19 namespace internal {
20 
21 class CodeTracer final : public Malloced {
22  public:
CodeTracer(int isolate_id)23   explicit CodeTracer(int isolate_id) : file_(nullptr), scope_depth_(0) {
24     if (!ShouldRedirect()) {
25       file_ = stdout;
26       return;
27     }
28 
29     if (FLAG_redirect_code_traces_to != nullptr) {
30       base::StrNCpy(filename_, FLAG_redirect_code_traces_to,
31                     filename_.length());
32     } else if (isolate_id >= 0) {
33       base::SNPrintF(filename_, "code-%d-%d.asm",
34                      base::OS::GetCurrentProcessId(), isolate_id);
35     } else {
36       base::SNPrintF(filename_, "code-%d.asm", base::OS::GetCurrentProcessId());
37     }
38 
39     WriteChars(filename_.begin(), "", 0, false);
40   }
41 
42   class V8_NODISCARD Scope {
43    public:
Scope(CodeTracer * tracer)44     explicit Scope(CodeTracer* tracer) : tracer_(tracer) { tracer->OpenFile(); }
~Scope()45     ~Scope() { tracer_->CloseFile(); }
46 
file()47     FILE* file() const { return tracer_->file(); }
48 
49    private:
50     CodeTracer* tracer_;
51   };
52 
53   class V8_NODISCARD StreamScope : public Scope {
54    public:
StreamScope(CodeTracer * tracer)55     explicit StreamScope(CodeTracer* tracer) : Scope(tracer) {
56       FILE* file = this->file();
57       if (file == stdout) {
58         stdout_stream_.emplace();
59       } else {
60         file_stream_.emplace(file);
61       }
62     }
63 
stream()64     std::ostream& stream() {
65       if (stdout_stream_.has_value()) return stdout_stream_.value();
66       return file_stream_.value();
67     }
68 
69    private:
70     // Exactly one of these two will be initialized.
71     base::Optional<StdoutStream> stdout_stream_;
72     base::Optional<OFStream> file_stream_;
73   };
74 
OpenFile()75   void OpenFile() {
76     if (!ShouldRedirect()) {
77       return;
78     }
79 
80     if (file_ == nullptr) {
81       file_ = base::OS::FOpen(filename_.begin(), "ab");
82       CHECK_WITH_MSG(file_ != nullptr,
83                      "could not open file. If on Android, try passing "
84                      "--redirect-code-traces-to=/sdcard/Download/<file-name>");
85     }
86 
87     scope_depth_++;
88   }
89 
CloseFile()90   void CloseFile() {
91     if (!ShouldRedirect()) {
92       return;
93     }
94 
95     if (--scope_depth_ == 0) {
96       DCHECK_NOT_NULL(file_);
97       base::Fclose(file_);
98       file_ = nullptr;
99     }
100   }
101 
file()102   FILE* file() const { return file_; }
103 
104  private:
ShouldRedirect()105   static bool ShouldRedirect() { return FLAG_redirect_code_traces; }
106 
107   base::EmbeddedVector<char, 128> filename_;
108   FILE* file_;
109   int scope_depth_;
110 };
111 
112 }  // namespace internal
113 }  // namespace v8
114 
115 #endif  // V8_DIAGNOSTICS_CODE_TRACER_H_
116