1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_COMPILER_JIT_COMPILER_H_
6#define RUNTIME_VM_COMPILER_JIT_COMPILER_H_
7
8#include "vm/allocation.h"
9#include "vm/compiler/api/deopt_id.h"
10#include "vm/growable_array.h"
11#include "vm/runtime_entry.h"
12#include "vm/thread_pool.h"
13
14namespace dart {
15
16// Forward declarations.
17class BackgroundCompilationQueue;
18class Class;
19class Code;
20class CompilationWorkQueue;
21class FlowGraph;
22class Function;
23class IndirectGotoInstr;
24class Library;
25class ParsedFunction;
26class QueueElement;
27class Script;
28class SequenceNode;
29
30class CompilationPipeline : public ZoneAllocated {
31 public:
32 static CompilationPipeline* New(Zone* zone, const Function& function);
33
34 virtual void ParseFunction(ParsedFunction* parsed_function) = 0;
35 virtual FlowGraph* BuildFlowGraph(
36 Zone* zone,
37 ParsedFunction* parsed_function,
38 ZoneGrowableArray<const ICData*>* ic_data_array,
39 intptr_t osr_id,
40 bool optimized) = 0;
41 virtual ~CompilationPipeline() {}
42};
43
44class DartCompilationPipeline : public CompilationPipeline {
45 public:
46 void ParseFunction(ParsedFunction* parsed_function) override;
47
48 FlowGraph* BuildFlowGraph(Zone* zone,
49 ParsedFunction* parsed_function,
50 ZoneGrowableArray<const ICData*>* ic_data_array,
51 intptr_t osr_id,
52 bool optimized) override;
53};
54
55class IrregexpCompilationPipeline : public CompilationPipeline {
56 public:
57 IrregexpCompilationPipeline() : backtrack_goto_(NULL) {}
58
59 void ParseFunction(ParsedFunction* parsed_function) override;
60
61 FlowGraph* BuildFlowGraph(Zone* zone,
62 ParsedFunction* parsed_function,
63 ZoneGrowableArray<const ICData*>* ic_data_array,
64 intptr_t osr_id,
65 bool optimized) override;
66
67 private:
68 IndirectGotoInstr* backtrack_goto_;
69};
70
71class Compiler : public AllStatic {
72 public:
73 static const intptr_t kNoOSRDeoptId = DeoptId::kNone;
74
75 static bool IsBackgroundCompilation();
76 // The result for a function may change if debugging gets turned on/off.
77 static bool CanOptimizeFunction(Thread* thread, const Function& function);
78
79 // Generates code for given function without optimization and sets its code
80 // field.
81 //
82 // Returns the raw code object if compilation succeeds. Otherwise returns a
83 // RawError. Also installs the generated code on the function.
84 static ObjectPtr CompileFunction(Thread* thread, const Function& function);
85
86 // Generates unoptimized code if not present, current code is unchanged.
87 // Bytecode is considered unoptimized code.
88 // TODO(regis): Revisit when deoptimizing mixed bytecode and jitted code.
89 static ErrorPtr EnsureUnoptimizedCode(Thread* thread,
90 const Function& function);
91
92 // Generates optimized code for function.
93 //
94 // Returns the code object if compilation succeeds. Returns an Error if
95 // there is a compilation error. If optimization fails, but there is no
96 // error, returns null. Any generated code is installed unless we are in
97 // OSR mode.
98 static ObjectPtr CompileOptimizedFunction(Thread* thread,
99 const Function& function,
100 intptr_t osr_id = kNoOSRDeoptId);
101
102 // Generates local var descriptors and sets it in 'code'. Do not call if the
103 // local var descriptor already exists.
104 static void ComputeLocalVarDescriptors(const Code& code);
105
106 // Eagerly compiles all functions in a class.
107 //
108 // Returns Error::null() if there is no compilation error.
109 static ErrorPtr CompileAllFunctions(const Class& cls);
110
111 // Eagerly read all bytecode.
112 static ErrorPtr ReadAllBytecode(const Class& cls);
113
114 // Notify the compiler that background (optimized) compilation has failed
115 // because the mutator thread changed the state (e.g., deoptimization,
116 // deferred loading). The background compilation may retry to compile
117 // the same function later.
118 static void AbortBackgroundCompilation(intptr_t deopt_id, const char* msg);
119};
120
121// Class to run optimizing compilation in a background thread.
122// Current implementation: one task per isolate, it dies with the owning
123// isolate.
124// No OSR compilation in the background compiler.
125class BackgroundCompiler {
126 public:
127 explicit BackgroundCompiler(Isolate* isolate, bool optimizing);
128 virtual ~BackgroundCompiler();
129
130 static void Start(Isolate* isolate) {
131 ASSERT(Thread::Current()->IsMutatorThread());
132 if (FLAG_enable_interpreter && isolate->background_compiler() != NULL) {
133 isolate->background_compiler()->Start();
134 }
135 if (isolate->optimizing_background_compiler() != NULL) {
136 isolate->optimizing_background_compiler()->Start();
137 }
138 }
139 static void Stop(Isolate* isolate) {
140 ASSERT(Thread::Current()->IsMutatorThread());
141 if (FLAG_enable_interpreter && isolate->background_compiler() != NULL) {
142 isolate->background_compiler()->Stop();
143 }
144 if (isolate->optimizing_background_compiler() != NULL) {
145 isolate->optimizing_background_compiler()->Stop();
146 }
147 }
148 static void Enable(Isolate* isolate) {
149 ASSERT(Thread::Current()->IsMutatorThread());
150 if (FLAG_enable_interpreter && isolate->background_compiler() != NULL) {
151 isolate->background_compiler()->Enable();
152 }
153 if (isolate->optimizing_background_compiler() != NULL) {
154 isolate->optimizing_background_compiler()->Enable();
155 }
156 }
157 static void Disable(Isolate* isolate) {
158 ASSERT(Thread::Current()->IsMutatorThread());
159 if (FLAG_enable_interpreter && isolate->background_compiler() != NULL) {
160 isolate->background_compiler()->Disable();
161 }
162 if (isolate->optimizing_background_compiler() != NULL) {
163 isolate->optimizing_background_compiler()->Disable();
164 }
165 }
166 static bool IsDisabled(Isolate* isolate, bool optimizing_compiler) {
167 ASSERT(Thread::Current()->IsMutatorThread());
168 if (optimizing_compiler) {
169 if (isolate->optimizing_background_compiler() != NULL) {
170 return isolate->optimizing_background_compiler()->IsDisabled();
171 }
172 } else {
173 if (FLAG_enable_interpreter && isolate->background_compiler() != NULL) {
174 return isolate->background_compiler()->IsDisabled();
175 }
176 }
177 return false;
178 }
179
180 // Call to compile (unoptimized or optimized) a function in the background,
181 // enters the function in the compilation queue.
182 void Compile(const Function& function);
183
184 void VisitPointers(ObjectPointerVisitor* visitor);
185
186 BackgroundCompilationQueue* function_queue() const { return function_queue_; }
187 bool is_running() const { return running_; }
188 bool is_optimizing() const { return optimizing_; }
189
190 void Run();
191
192 private:
193 void Start();
194 void Stop();
195 void Enable();
196 void Disable();
197 bool IsDisabled();
198 bool IsRunning() { return !done_; }
199
200 Isolate* isolate_;
201
202 Monitor queue_monitor_; // Controls access to the queue.
203 BackgroundCompilationQueue* function_queue_;
204
205 Monitor done_monitor_; // Notify/wait that the thread is done.
206 bool running_; // While true, will try to read queue and compile.
207 bool done_; // True if the thread is done.
208 bool optimizing_;
209
210 int16_t disabled_depth_;
211
212 DISALLOW_IMPLICIT_CONSTRUCTORS(BackgroundCompiler);
213};
214
215} // namespace dart
216
217#endif // RUNTIME_VM_COMPILER_JIT_COMPILER_H_
218